HaikuDepot: Text stuff: Support for simple bullet lists.

Also:
 * Fixed off-by-one bug when extracting wrapped TextSpans until the
   line's end text offset.
 * ParagraphStyle::FirstLineInset() is now additional to LineInset().
 * Potential Bullet::Spacing() is added to all lines as inset.
This commit is contained in:
Stephan Aßmus
2013-09-05 22:07:44 +02:00
parent ccfedbc4fa
commit 6576e6c774
11 changed files with 358 additions and 10 deletions
+2
View File
@@ -13,6 +13,8 @@ for sourceDir in $(sourceDirs) {
}
local textDocumentSources =
Bullet.cpp
BulletData.cpp
CharacterStyle.cpp
CharacterStyleData.cpp
Paragraph.cpp
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright 2013, Stephan Aßmus <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "Bullet.h"
static BulletData sEmptyBullet;
Bullet::Bullet()
:
fBulletData(&sEmptyBullet)
{
}
Bullet::Bullet(const BString& string, float spacing)
:
fBulletData(new BulletData(string, spacing), true)
{
}
Bullet::Bullet(const Bullet& other)
:
fBulletData(other.fBulletData)
{
}
Bullet&
Bullet::operator=(const Bullet& other)
{
if (this == &other)
return *this;
fBulletData = other.fBulletData;
return *this;
}
bool
Bullet::operator==(const Bullet& other) const
{
if (this == &other)
return true;
if (fBulletData == other.fBulletData)
return true;
if (fBulletData.Get() != NULL && other.fBulletData.Get() != NULL)
return *fBulletData.Get() == *other.fBulletData.Get();
return false;
}
bool
Bullet::operator!=(const Bullet& other) const
{
return !(*this == other);
}
bool
Bullet::SetString(const BString& string)
{
BulletDataRef data = fBulletData->SetString(string);
if (data == fBulletData)
return data->String() == string;
fBulletData = data;
return true;
}
const BString&
Bullet::String() const
{
return fBulletData->String();
}
bool
Bullet::SetSpacing(float spacing)
{
BulletDataRef data = fBulletData->SetSpacing(spacing);
if (data == fBulletData)
return data->Spacing() == spacing;
fBulletData = data;
return true;
}
float
Bullet::Spacing() const
{
return fBulletData->Spacing();
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright 2013, Stephan Aßmus <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef BULLET_H
#define BULLET_H
#include "BulletData.h"
class Bullet {
public:
Bullet();
Bullet(const BString& string, float spacing);
Bullet(const Bullet& other);
Bullet& operator=(const Bullet& other);
bool operator==(const Bullet& other) const;
bool operator!=(const Bullet& other) const;
bool SetString(const BString& string);
const BString& String() const;
bool SetSpacing(float spacing);
float Spacing() const;
private:
BulletDataRef fBulletData;
};
#endif // BULLET_H
@@ -0,0 +1,90 @@
/*
* Copyright 2013, Stephan Aßmus <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "BulletData.h"
#include <new>
BulletData::BulletData()
:
fString(""),
fSpacing(0.0f)
{
}
BulletData::BulletData(const BString& string, float spacing)
:
fString(string),
fSpacing(spacing)
{
}
BulletData::BulletData(const BulletData& other)
:
fString(other.fString),
fSpacing(other.fSpacing)
{
}
bool
BulletData::operator==(const BulletData& other) const
{
if (this == &other)
return true;
return fString == other.fString
&& fSpacing == other.fSpacing;
}
bool
BulletData::operator!=(const BulletData& other) const
{
return !(*this == other);
}
BulletDataRef
BulletData::SetString(const BString& string)
{
if (fString == string)
return BulletDataRef(this);
BulletData* ret = new(std::nothrow) BulletData(*this);
if (ret == NULL)
return BulletDataRef(this);
ret->fString = string;
return BulletDataRef(ret, true);
}
BulletDataRef
BulletData::SetSpacing(float spacing)
{
if (fSpacing == spacing)
return BulletDataRef(this);
BulletData* ret = new(std::nothrow) BulletData(*this);
if (ret == NULL)
return BulletDataRef(this);
ret->fSpacing = spacing;
return BulletDataRef(ret, true);
}
// #pragma mark - private
BulletData&
BulletData::operator=(const BulletData& other)
{
return *this;
}
@@ -0,0 +1,46 @@
/*
* Copyright 2013, Stephan Aßmus <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef BULLET_DATA_H
#define BULLET_DATA_H
#include <Referenceable.h>
#include <String.h>
class BulletData;
typedef BReference<BulletData> BulletDataRef;
// You cannot modify a BulletData object once it has been created.
class BulletData : public BReferenceable {
public:
BulletData();
BulletData(const BString& string,
float spacing);
BulletData(const BulletData& other);
bool operator==(
const BulletData& other) const;
bool operator!=(
const BulletData& other) const;
BulletDataRef SetString(const BString& string);
inline const BString& String() const
{ return fString; }
BulletDataRef SetSpacing(float spacing);
inline float Spacing() const
{ return fSpacing; }
private:
BulletData& operator=(const BulletData& other);
private:
BString fString;
float fSpacing;
};
#endif // BULLET_DATA_H
@@ -257,6 +257,17 @@ ParagraphLayout::Draw(BView* view, const BPoint& offset)
const LineInfo& line = fLineInfos.ItemAtFast(i);
_DrawLine(view, offset, line);
}
const Bullet& bullet = fParagraphStyle.Bullet();
if (bullet.Spacing() > 0.0f && bullet.String().Length() > 0) {
// Draw bullet at offset
view->SetHighColor(0, 0, 0, 255);
BPoint bulletPos(offset);
bulletPos.x += fParagraphStyle.FirstLineInset()
+ fParagraphStyle.LineInset();
bulletPos.y += fLineInfos.ItemAt(0).maxAscent;
view->DrawString(bullet.String(), bulletPos);
}
}
@@ -295,7 +306,10 @@ ParagraphLayout::_Layout()
{
fLineInfos.Clear();
float x = fParagraphStyle.FirstLineInset();
const Bullet& bullet = fParagraphStyle.Bullet();
float x = fParagraphStyle.LineInset() + fParagraphStyle.FirstLineInset()
+ bullet.Spacing();
float y = 0.0f;
int lineIndex = 0;
int lineStart = 0;
@@ -388,7 +402,7 @@ ParagraphLayout::_Layout()
_FinalizeLine(lineStart, lineEnd, lineIndex, y, lineHeight);
// Start position of the next line
x = fParagraphStyle.LineInset();
x = fParagraphStyle.LineInset() + bullet.Spacing();
y += lineHeight + fParagraphStyle.LineSpacing();
if (lineBreak)
@@ -642,7 +656,7 @@ ParagraphLayout::_FinalizeLine(int lineStart, int lineEnd, int lineIndex,
if (addSpan) {
const TextSpan& span = fTextSpans.ItemAt(spanIndex);
TextSpan subSpan = span.SubSpan(i - spanStart,
(lineEnd - spanStart) - (i - spanStart));
(lineEnd - spanStart + 1) - (i - spanStart));
line.layoutedSpans.Add(subSpan);
_IncludeStyleInLine(line, span.Style());
}
@@ -187,3 +187,22 @@ ParagraphStyle::SpacingBottom() const
}
bool
ParagraphStyle::SetBullet(const ::Bullet& bullet)
{
ParagraphStyleDataRef data = fStyleData->SetBullet(bullet);
if (data == fStyleData)
return data->Bullet() == bullet;
fStyleData = data;
return true;
}
const ::Bullet&
ParagraphStyle::Bullet() const
{
return fStyleData->Bullet();
}
@@ -38,6 +38,8 @@ public:
bool SetSpacingBottom(float spacing);
float SpacingBottom() const;
bool SetBullet(const ::Bullet& bullet);
const ::Bullet& Bullet() const;
private:
ParagraphStyleDataRef fStyleData;
@@ -17,7 +17,9 @@ ParagraphStyleData::ParagraphStyleData()
fLineInset(0.0f),
fSpacingTop(0.0f),
fSpacingBottom(0.0f)
fSpacingBottom(0.0f),
fBullet()
{
}
@@ -31,7 +33,9 @@ ParagraphStyleData::ParagraphStyleData(const ParagraphStyleData& other)
fLineInset(other.fLineInset),
fSpacingTop(other.fSpacingTop),
fSpacingBottom(other.fSpacingBottom)
fSpacingBottom(other.fSpacingBottom),
fBullet(other.fBullet)
{
}
@@ -47,7 +51,8 @@ ParagraphStyleData::operator==(const ParagraphStyleData& other) const
&& fFirstLineInset == other.fFirstLineInset
&& fLineInset == other.fLineInset
&& fSpacingTop == other.fSpacingTop
&& fSpacingBottom == other.fSpacingBottom;
&& fSpacingBottom == other.fSpacingBottom
&& fBullet == other.fBullet;
}
@@ -163,6 +168,21 @@ ParagraphStyleData::SetSpacingBottom(float spacing)
}
ParagraphStyleDataRef
ParagraphStyleData::SetBullet(const ::Bullet& bullet)
{
if (fBullet == bullet)
return ParagraphStyleDataRef(this);
ParagraphStyleData* ret = new(std::nothrow) ParagraphStyleData(*this);
if (ret == NULL)
return ParagraphStyleDataRef(this);
ret->fBullet = bullet;
return ParagraphStyleDataRef(ret, true);
}
// #pragma mark - private
@@ -5,7 +5,7 @@
#ifndef PARAGRAPH_STYLE_DATA_H
#define PARAGRAPH_STYLE_DATA_H
#include <Referenceable.h>
#include "Bullet.h"
enum Alignment {
@@ -60,6 +60,9 @@ public:
inline float SpacingBottom() const
{ return fSpacingBottom; }
ParagraphStyleDataRef SetBullet(const ::Bullet& bullet);
inline const ::Bullet& Bullet() const
{ return fBullet; }
private:
ParagraphStyleData& operator=(const ParagraphStyleData& other);
@@ -73,6 +76,8 @@ private:
float fSpacingTop;
float fSpacingBottom;
::Bullet fBullet;
};
@@ -53,9 +53,9 @@ TextDocumentTest::ReadyToRun()
TextDocumentRef document(new TextDocument(), true);
Paragraph paragraph(paragraphStyle);
paragraph.Append(TextSpan("This is a ", regularStyle));
paragraph.Append(TextSpan("test", bigStyle));
paragraph.Append(TextSpan(" to see if ", regularStyle));
paragraph.Append(TextSpan("This is a", regularStyle));
paragraph.Append(TextSpan(" test ", bigStyle));
paragraph.Append(TextSpan("to see if ", regularStyle));
paragraph.Append(TextSpan("different", boldStyle));
paragraph.Append(TextSpan(" character styles already work.", regularStyle));
document->Append(paragraph);
@@ -70,6 +70,22 @@ TextDocumentTest::ReadyToRun()
paragraph.Append(TextSpan(" supported as of now!", regularStyle));
document->Append(paragraph);
// Test a bullet list
paragraphStyle.SetSpacingTop(8.0f);
paragraphStyle.SetAlignment(ALIGN_LEFT);
paragraphStyle.SetJustify(true);
paragraphStyle.SetBullet(Bullet("", 12.0f));
paragraphStyle.SetLineInset(10.0f);
paragraph = Paragraph(paragraphStyle);
paragraph.Append(TextSpan("Even bullet lists are supported.", regularStyle));
document->Append(paragraph);
paragraph = Paragraph(paragraphStyle);
paragraph.Append(TextSpan("The wrapping in this bullet item should "
"look visually pleasing. And why should it not?", regularStyle));
document->Append(paragraph);
documentView->SetTextDocument(document);
window->Show();