HaikuDepot: More work on custom TextView
* TextLayout produces some first visible results...
This commit is contained in:
parent
156881a46b
commit
0f71004390
@ -25,6 +25,7 @@ Application HaikuDepot :
|
||||
support.cpp
|
||||
|
||||
TextLayout.cpp
|
||||
TextStyle.cpp
|
||||
TextView.cpp
|
||||
|
||||
: be translation libcolumnlistview.a libshared.a $(TARGET_LIBSUPC++)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <StringView.h>
|
||||
|
||||
#include "PackageManager.h"
|
||||
#include "TextView.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
@ -733,12 +734,11 @@ public:
|
||||
fPackageVersionView->SetFont(&versionFont);
|
||||
fPackageVersionView->SetHighColor(kLightBlack);
|
||||
|
||||
fTextView = new BTextView("rating text");
|
||||
fTextView = new TextView("rating text");
|
||||
fTextView->SetViewColor(ViewColor());
|
||||
fTextView->MakeEditable(false);
|
||||
fTextView->SetText(rating.Comment());
|
||||
const float textInset = be_plain_font->Size();
|
||||
fTextView->SetInsets(0.0f, floorf(textInset / 2), textInset, 0.0f);
|
||||
// const float textInset = be_plain_font->Size();
|
||||
// fTextView->SetInsets(0.0f, floorf(textInset / 2), textInset, 0.0f);
|
||||
|
||||
BLayoutBuilder::Group<>(this)
|
||||
.Add(fAvatarView, 0.2f)
|
||||
@ -763,7 +763,7 @@ private:
|
||||
RatingView* fRatingView;
|
||||
BStringView* fRatingLabelView;
|
||||
BStringView* fPackageVersionView;
|
||||
BTextView* fTextView;
|
||||
TextView* fTextView;
|
||||
};
|
||||
|
||||
|
||||
|
100
src/apps/haiku-depot/textview/GlyphInfo.h
Normal file
100
src/apps/haiku-depot/textview/GlyphInfo.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef GLYPH_INFO_H
|
||||
#define GLYPH_INFO_H
|
||||
|
||||
#include "TextStyle.h"
|
||||
|
||||
|
||||
class GlyphInfo {
|
||||
public:
|
||||
GlyphInfo()
|
||||
:
|
||||
charCode(0),
|
||||
x(0.0f),
|
||||
y(0.0f),
|
||||
advanceX(0.0f),
|
||||
maxAscend(0.0f),
|
||||
maxDescend(0.0f),
|
||||
lineIndex(0),
|
||||
style()
|
||||
{
|
||||
}
|
||||
|
||||
GlyphInfo(uint32 charCode, float x, float y, float advanceX,
|
||||
float maxAscend, float maxDescend, int lineIndex,
|
||||
const TextStyleRef& style)
|
||||
:
|
||||
charCode(charCode),
|
||||
x(x),
|
||||
y(y),
|
||||
advanceX(advanceX),
|
||||
maxAscend(maxAscend),
|
||||
maxDescend(maxDescend),
|
||||
lineIndex(lineIndex),
|
||||
style(style)
|
||||
{
|
||||
}
|
||||
|
||||
GlyphInfo(const GlyphInfo& other)
|
||||
:
|
||||
charCode(other.charCode),
|
||||
x(other.x),
|
||||
y(other.y),
|
||||
advanceX(other.advanceX),
|
||||
maxAscend(other.maxAscend),
|
||||
maxDescend(other.maxDescend),
|
||||
lineIndex(other.lineIndex),
|
||||
style(other.style)
|
||||
{
|
||||
}
|
||||
|
||||
GlyphInfo& operator=(const GlyphInfo& other)
|
||||
{
|
||||
charCode = other.charCode;
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
advanceX = other.advanceX;
|
||||
maxAscend = other.maxAscend;
|
||||
maxDescend = other.maxDescend;
|
||||
lineIndex = other.lineIndex;
|
||||
style = other.style;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const GlyphInfo& other) const
|
||||
{
|
||||
return charCode == other.charCode
|
||||
&& x == other.x
|
||||
&& y == other.y
|
||||
&& advanceX == other.advanceX
|
||||
&& maxAscend == other.maxAscend
|
||||
&& maxDescend == other.maxDescend
|
||||
&& lineIndex == other.lineIndex
|
||||
&& style == other.style;
|
||||
}
|
||||
|
||||
bool operator!=(const GlyphInfo& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
public:
|
||||
uint32 charCode;
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float advanceX;
|
||||
|
||||
float maxAscend;
|
||||
float maxDescend;
|
||||
|
||||
int lineIndex;
|
||||
|
||||
TextStyleRef style;
|
||||
};
|
||||
|
||||
|
||||
#endif // GLYPH_INFO_H
|
80
src/apps/haiku-depot/textview/LineInfo.h
Normal file
80
src/apps/haiku-depot/textview/LineInfo.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef LINE_INFO_H
|
||||
#define LINE_INFO_H
|
||||
|
||||
#include "List.h"
|
||||
|
||||
|
||||
class LineInfo {
|
||||
public:
|
||||
LineInfo()
|
||||
:
|
||||
textOffset(0),
|
||||
y(0.0f),
|
||||
height(0.0f),
|
||||
maxAscent(0.0f),
|
||||
maxDescent(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
LineInfo(int textOffset, float y, float height, float maxAscent,
|
||||
float maxDescent)
|
||||
:
|
||||
textOffset(textOffset),
|
||||
y(y),
|
||||
height(height),
|
||||
maxAscent(maxAscent),
|
||||
maxDescent(maxDescent)
|
||||
{
|
||||
}
|
||||
|
||||
LineInfo(const LineInfo& other)
|
||||
:
|
||||
textOffset(other.textOffset),
|
||||
y(other.y),
|
||||
height(other.height),
|
||||
maxAscent(other.maxAscent),
|
||||
maxDescent(other.maxDescent)
|
||||
{
|
||||
}
|
||||
|
||||
LineInfo& operator=(const LineInfo& other)
|
||||
{
|
||||
textOffset = other.textOffset;
|
||||
y = other.y;
|
||||
height = other.height;
|
||||
maxAscent = other.maxAscent;
|
||||
maxDescent = other.maxDescent;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const LineInfo& other) const
|
||||
{
|
||||
return textOffset == other.textOffset
|
||||
&& y == other.y
|
||||
&& height == other.height
|
||||
&& maxAscent == other.maxAscent
|
||||
&& maxDescent == other.maxDescent;
|
||||
}
|
||||
|
||||
bool operator!=(const LineInfo& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
public:
|
||||
int textOffset;
|
||||
float y;
|
||||
float height;
|
||||
float maxAscent;
|
||||
float maxDescent;
|
||||
};
|
||||
|
||||
|
||||
typedef List<LineInfo, false> LineInfoList;
|
||||
|
||||
|
||||
#endif // LINE_INFO_H
|
@ -6,12 +6,15 @@
|
||||
#include "TextLayout.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <utf8_functions.h>
|
||||
#include <View.h>
|
||||
|
||||
#include "GlyphInfo.h"
|
||||
#include "List.h"
|
||||
#include "TextStyle.h"
|
||||
|
||||
|
||||
enum {
|
||||
@ -26,7 +29,7 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
static uint32
|
||||
inline uint32
|
||||
get_char_classification(uint32 charCode)
|
||||
{
|
||||
// TODO: Should check against a list of characters containing also
|
||||
@ -87,185 +90,6 @@ get_char_classification(uint32 charCode)
|
||||
}
|
||||
|
||||
|
||||
class Style : public BReferenceable {
|
||||
public:
|
||||
Style(const BFont& font, float ascent, float descent, float width,
|
||||
rgb_color fgColor, rgb_color bgColor, bool strikeOut,
|
||||
rgb_color strikeOutColor, bool underline,
|
||||
uint32 underlineStyle, rgb_color underlineColor)
|
||||
:
|
||||
font(font),
|
||||
|
||||
ascent(ascent),
|
||||
descent(descent),
|
||||
width(width),
|
||||
|
||||
fgColor(fgColor),
|
||||
bgColor(bgColor),
|
||||
|
||||
strikeOut(strikeOut),
|
||||
strikeOutColor(strikeOutColor),
|
||||
|
||||
underline(underline),
|
||||
underlineStyle(underlineStyle),
|
||||
underlineColor(underlineColor)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
BFont font;
|
||||
|
||||
// The following three values override glyph metrics unless -1
|
||||
float ascent;
|
||||
float descent;
|
||||
float width;
|
||||
|
||||
rgb_color fgColor;
|
||||
rgb_color bgColor;
|
||||
|
||||
bool strikeOut;
|
||||
rgb_color strikeOutColor;
|
||||
|
||||
bool underline;
|
||||
uint32 underlineStyle;
|
||||
rgb_color underlineColor;
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<Style> StyleRef;
|
||||
|
||||
|
||||
class GlyphInfo {
|
||||
public:
|
||||
GlyphInfo(uint32 charCode, float x, float y, float advanceX,
|
||||
float maxAscend, float maxDescend, int lineIndex,
|
||||
const StyleRef& style)
|
||||
:
|
||||
charCode(charCode),
|
||||
x(x),
|
||||
y(y),
|
||||
advanceX(advanceX),
|
||||
maxAscend(maxAscend),
|
||||
maxDescend(maxDescend),
|
||||
lineIndex(lineIndex),
|
||||
style(style)
|
||||
{
|
||||
}
|
||||
|
||||
GlyphInfo(const GlyphInfo& other)
|
||||
:
|
||||
charCode(other.charCode),
|
||||
x(other.x),
|
||||
y(other.y),
|
||||
advanceX(other.advanceX),
|
||||
maxAscend(other.maxAscend),
|
||||
maxDescend(other.maxDescend),
|
||||
lineIndex(other.lineIndex),
|
||||
style(other.style)
|
||||
{
|
||||
}
|
||||
|
||||
GlyphInfo& operator=(const GlyphInfo& other)
|
||||
{
|
||||
charCode = other.charCode;
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
advanceX = other.advanceX;
|
||||
maxAscend = other.maxAscend;
|
||||
maxDescend = other.maxDescend;
|
||||
lineIndex = other.lineIndex;
|
||||
style = other.style;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const GlyphInfo& other) const
|
||||
{
|
||||
return charCode == other.charCode
|
||||
&& x == other.x
|
||||
&& y == other.y
|
||||
&& advanceX == other.advanceX
|
||||
&& maxAscend == other.maxAscend
|
||||
&& maxDescend == other.maxDescend
|
||||
&& lineIndex == other.lineIndex
|
||||
&& style == other.style;
|
||||
}
|
||||
|
||||
bool operator!=(const GlyphInfo& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
public:
|
||||
uint32 charCode;
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float advanceX;
|
||||
|
||||
float maxAscend;
|
||||
float maxDescend;
|
||||
|
||||
int lineIndex;
|
||||
|
||||
StyleRef style;
|
||||
};
|
||||
|
||||
|
||||
class Line {
|
||||
public:
|
||||
Line()
|
||||
:
|
||||
textOffset(0),
|
||||
y(0.0f),
|
||||
height(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
Line(int textOffset, float y, float height)
|
||||
:
|
||||
textOffset(textOffset),
|
||||
y(y),
|
||||
height(height)
|
||||
{
|
||||
}
|
||||
|
||||
Line(const Line& other)
|
||||
:
|
||||
textOffset(other.textOffset),
|
||||
y(other.y),
|
||||
height(other.height)
|
||||
{
|
||||
}
|
||||
|
||||
Line& operator=(const Line& other)
|
||||
{
|
||||
textOffset = other.textOffset;
|
||||
y = other.y;
|
||||
height = other.height;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Line& other) const
|
||||
{
|
||||
return textOffset == other.textOffset
|
||||
&& y == other.y
|
||||
&& height == other.height;
|
||||
}
|
||||
|
||||
bool operator!=(const Line& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
public:
|
||||
int textOffset;
|
||||
float y;
|
||||
float height;
|
||||
float maxAscent;
|
||||
float maxDescent;
|
||||
};
|
||||
|
||||
|
||||
inline bool
|
||||
can_end_line(const GlyphInfo* buffer, int offset, int count)
|
||||
{
|
||||
@ -329,76 +153,6 @@ can_end_line(const GlyphInfo* buffer, int offset, int count)
|
||||
}
|
||||
|
||||
|
||||
class TextLayout::Layout {
|
||||
public:
|
||||
Layout(TextLayout* textLayout)
|
||||
:
|
||||
fTextLayout(textLayout)
|
||||
{
|
||||
}
|
||||
|
||||
void ComputeLayout()
|
||||
{
|
||||
ComputeLayout(fTextLayout->fText, fTextLayout->fDefaultFont,
|
||||
fTextLayout->fWidth);
|
||||
}
|
||||
|
||||
void ComputeLayout(const BString& text, const BFont& font, float width)
|
||||
{
|
||||
fLines.Clear();
|
||||
|
||||
int charCount = text.CountChars();
|
||||
if (charCount == 0)
|
||||
return;
|
||||
|
||||
// Allocate arrays
|
||||
float* escapementArray = new (std::nothrow) float[charCount];
|
||||
if (escapementArray == NULL)
|
||||
return;
|
||||
ArrayDeleter<float> escapementDeleter(escapementArray);
|
||||
|
||||
uint32* charArray = new (std::nothrow) uint32[charCount];
|
||||
if (charArray == NULL)
|
||||
return;
|
||||
ArrayDeleter<uint32> charDeleter(charArray);
|
||||
|
||||
// Fetch glyph spacing information
|
||||
font.GetEscapements(text.String(), charCount, escapementArray);
|
||||
|
||||
// Convert to glyph buffer
|
||||
const char* c = text.String();
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
charArray[i] = UTF8ToCharCode(&c);
|
||||
}
|
||||
|
||||
// float x = 0.0f;
|
||||
// float y = 0.0f;
|
||||
for (int i = 0; i < charCount; i++) {
|
||||
// TODO: ...
|
||||
}
|
||||
}
|
||||
|
||||
float Height() const
|
||||
{
|
||||
float height = fTextLayout->fDefaultFont.Size();
|
||||
if (fLines.CountItems() > 0) {
|
||||
const Line& lastLine = fLines.LastItem();
|
||||
height = lastLine.y + lastLine.height;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
void Draw(BView* view, const BPoint& offset) const
|
||||
{
|
||||
// TODO: ...
|
||||
}
|
||||
|
||||
private:
|
||||
TextLayout* fTextLayout;
|
||||
List<Line, false> fLines;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - TextLayout
|
||||
|
||||
|
||||
@ -406,12 +160,21 @@ TextLayout::TextLayout()
|
||||
:
|
||||
fText(),
|
||||
|
||||
fDefaultFont(be_plain_font),
|
||||
fDefaultFont(),
|
||||
fAscent(0.0f),
|
||||
fDescent(0.0f),
|
||||
fWidth(0.0f),
|
||||
fGlyphSpacing(0.0f),
|
||||
fFirstLineInset(0.0f),
|
||||
fLineInset(0.0f),
|
||||
fLineSpacing(0.0f),
|
||||
|
||||
fLayoutValid(false),
|
||||
fLayout(new (std::nothrow) Layout(this))
|
||||
fGlyphInfoBuffer(NULL),
|
||||
fGlyphInfoCount(0)
|
||||
{
|
||||
// Init fAscent and fDescent
|
||||
SetFont(BFont(be_plain_font));
|
||||
}
|
||||
|
||||
|
||||
@ -420,80 +183,363 @@ TextLayout::TextLayout(const TextLayout& other)
|
||||
fText(other.fText),
|
||||
|
||||
fDefaultFont(other.fDefaultFont),
|
||||
fAscent(other.fAscent),
|
||||
fDescent(other.fDescent),
|
||||
fWidth(other.fWidth),
|
||||
fGlyphSpacing(other.fGlyphSpacing),
|
||||
fFirstLineInset(other.fFirstLineInset),
|
||||
fLineInset(other.fLineInset),
|
||||
fLineSpacing(other.fLineSpacing),
|
||||
|
||||
fLayoutValid(false),
|
||||
fLayout(new (std::nothrow) Layout(this))
|
||||
fGlyphInfoBuffer(NULL),
|
||||
fGlyphInfoCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TextLayout::~TextLayout()
|
||||
{
|
||||
delete fLayout;
|
||||
delete[] fGlyphInfoBuffer;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::SetText(const BString& text)
|
||||
{
|
||||
if (fText == text)
|
||||
return;
|
||||
|
||||
fText = text;
|
||||
fLayoutValid = false;
|
||||
if (fText != text) {
|
||||
fText = text;
|
||||
fLayoutValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::SetFont(const BFont& font)
|
||||
{
|
||||
if (fDefaultFont == font)
|
||||
return;
|
||||
if (fDefaultFont != font) {
|
||||
fDefaultFont = font;
|
||||
|
||||
fDefaultFont = font;
|
||||
fLayoutValid = false;
|
||||
font_height fontHeight;
|
||||
font.GetHeight(&fontHeight);
|
||||
|
||||
fAscent = fontHeight.ascent;
|
||||
fDescent = fontHeight.descent;
|
||||
|
||||
fLayoutValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::SetGlyphSpacing(float glyphSpacing)
|
||||
{
|
||||
if (fGlyphSpacing != glyphSpacing) {
|
||||
fGlyphSpacing = glyphSpacing;
|
||||
fLayoutValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::SetFirstLineInset(float inset)
|
||||
{
|
||||
if (fFirstLineInset != inset) {
|
||||
fFirstLineInset = inset;
|
||||
fLayoutValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::SetLineInset(float inset)
|
||||
{
|
||||
if (fLineInset != inset) {
|
||||
fLineInset = inset;
|
||||
fLayoutValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::SetWidth(float width)
|
||||
{
|
||||
if (fWidth == width)
|
||||
return;
|
||||
|
||||
fWidth = width;
|
||||
fLayoutValid = false;
|
||||
if (fWidth != width) {
|
||||
fWidth = width;
|
||||
fLayoutValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
TextLayout::Height()
|
||||
{
|
||||
if (_ValidateLayout())
|
||||
return fLayout->Height();
|
||||
return 0.0f;
|
||||
_ValidateLayout();
|
||||
|
||||
float height = fDefaultFont.Size();
|
||||
|
||||
if (fLineInfos.CountItems() > 0) {
|
||||
const LineInfo& lastLine = fLineInfos.LastItem();
|
||||
height = lastLine.y + lastLine.height;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::Draw(BView* view, const BPoint& offset)
|
||||
{
|
||||
if (_ValidateLayout())
|
||||
fLayout->Draw(view, offset);
|
||||
_ValidateLayout();
|
||||
|
||||
// TODO: Support styles and all
|
||||
view->SetFont(&fDefaultFont);
|
||||
view->SetHighColor(0, 0, 0);
|
||||
|
||||
int lineCount = fLineInfos.CountItems();
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
const LineInfo& line = fLineInfos.ItemAtFast(i);
|
||||
|
||||
int startOffset = line.textOffset;
|
||||
int endOffset;
|
||||
if (i < lineCount - 1) {
|
||||
const LineInfo& nextLine = fLineInfos.ItemAtFast(i + 1);
|
||||
endOffset = nextLine.textOffset;
|
||||
} else {
|
||||
endOffset = fGlyphInfoCount;
|
||||
}
|
||||
|
||||
BString string;
|
||||
fText.CopyCharsInto(string, startOffset, endOffset - startOffset);
|
||||
|
||||
float x = fGlyphInfoBuffer[startOffset].x;
|
||||
float y = fGlyphInfoBuffer[startOffset].y + line.maxAscent;
|
||||
view->DrawString(string, BPoint(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - private
|
||||
|
||||
|
||||
bool
|
||||
void
|
||||
TextLayout::_ValidateLayout()
|
||||
{
|
||||
if (!fLayoutValid && fLayout != NULL) {
|
||||
fLayout->ComputeLayout();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (!fLayoutValid)
|
||||
_Layout();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::_Layout()
|
||||
{
|
||||
fLineInfos.Clear();
|
||||
delete[] fGlyphInfoBuffer;
|
||||
fGlyphInfoBuffer = NULL;
|
||||
|
||||
fGlyphInfoCount = fText.CountChars();
|
||||
if (fGlyphInfoCount == 0)
|
||||
return;
|
||||
|
||||
// Allocate arrays
|
||||
float* escapementArray = new (std::nothrow) float[fGlyphInfoCount];
|
||||
if (escapementArray == NULL)
|
||||
return;
|
||||
ArrayDeleter<float> escapementDeleter(escapementArray);
|
||||
|
||||
// Fetch glyph spacing information
|
||||
fDefaultFont.GetEscapements(fText.String(), fGlyphInfoCount,
|
||||
escapementArray);
|
||||
|
||||
// Convert to glyph buffer
|
||||
fGlyphInfoBuffer = new (std::nothrow) GlyphInfo[fGlyphInfoCount];
|
||||
|
||||
// Init glyph buffer and convert escapement scale
|
||||
float size = fDefaultFont.Size();
|
||||
const char* c = fText.String();
|
||||
for (int i = 0; i < fGlyphInfoCount; i++) {
|
||||
fGlyphInfoBuffer[i].charCode = UTF8ToCharCode(&c);
|
||||
escapementArray[i] *= size;
|
||||
}
|
||||
|
||||
|
||||
float x = fFirstLineInset;
|
||||
float y = 0.0f;
|
||||
int lineIndex = 0;
|
||||
int lineStart = 0;
|
||||
|
||||
for (int i = 0; i < fGlyphInfoCount; i++) {
|
||||
uint32 charClassification = get_char_classification(
|
||||
fGlyphInfoBuffer[i].charCode);
|
||||
|
||||
float advanceX = 0.0f;
|
||||
float advanceY = 0.0f;
|
||||
_GetGlyphAdvance(i, advanceX, advanceY, escapementArray);
|
||||
|
||||
bool nextLine = false;
|
||||
bool lineBreak = false;
|
||||
|
||||
// if (fGlyphInfoBuffer[i].charCode == '\t') {
|
||||
// // Figure out tab width, it's the width between the last two tab
|
||||
// // stops.
|
||||
// float tabWidth = 0.0f;
|
||||
// if (fTabCount > 0)
|
||||
// tabWidth = fTabBuffer[fTabCount - 1];
|
||||
// if (fTabCount > 1)
|
||||
// tabWidth -= fTabBuffer[fTabCount - 2];
|
||||
//
|
||||
// // Try to find a tab stop that is farther than the current x
|
||||
// // offset
|
||||
// double tabOffset = 0.0;
|
||||
// for (unsigned tabIndex = 0; tabIndex < fTabCount; tabIndex++) {
|
||||
// tabOffset = fTabBuffer[tabIndex];
|
||||
// if (tabOffset > x)
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// // If no tab stop has been found, make the tab stop a multiple of
|
||||
// // the tab width
|
||||
// if (tabOffset <= x && tabWidth > 0.0)
|
||||
// tabOffset = ((int) (x / tabWidth) + 1) * tabWidth;
|
||||
//
|
||||
// if (tabOffset - x > 0.0)
|
||||
// advanceX = tabOffset - x;
|
||||
// }
|
||||
|
||||
fGlyphInfoBuffer[i].advanceX = advanceX;
|
||||
|
||||
if (fGlyphInfoBuffer[i].charCode == '\n') {
|
||||
nextLine = true;
|
||||
lineBreak = true;
|
||||
fGlyphInfoBuffer[i].x = x;
|
||||
fGlyphInfoBuffer[i].y = y;
|
||||
} else if (fWidth > 0.0f && x + advanceX > fWidth) {
|
||||
if (charClassification == CHAR_CLASS_WHITESPACE) {
|
||||
advanceX = 0.0f;
|
||||
} else if (i > lineStart) {
|
||||
nextLine = true;
|
||||
// The current glyph extends outside the width, we need to wrap
|
||||
// to the next line. See what previous offset can be the end
|
||||
// of the line.
|
||||
int lineEnd = i - 1;
|
||||
while (lineEnd > lineStart
|
||||
&& !can_end_line(fGlyphInfoBuffer, lineEnd,
|
||||
fGlyphInfoCount)) {
|
||||
lineEnd--;
|
||||
}
|
||||
|
||||
if (lineEnd > lineStart) {
|
||||
// Found a place to perform a line break.
|
||||
i = lineEnd + 1;
|
||||
// Adjust the glyph info to point at the changed buffer
|
||||
// position
|
||||
_GetGlyphAdvance(i, advanceX, advanceY, escapementArray);
|
||||
} else {
|
||||
// Just break where we are.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nextLine) {
|
||||
// * Initialize the max ascent/descent of all preceding glyph infos
|
||||
// on the current/last line
|
||||
// * Adjust the baseline offset according to the max ascent
|
||||
// * Fill in the line index.
|
||||
unsigned lineEnd;
|
||||
if (lineBreak)
|
||||
lineEnd = i;
|
||||
else
|
||||
lineEnd = i - 1;
|
||||
|
||||
float lineHeight = 0.0;
|
||||
_FinalizeLine(lineStart, lineEnd, lineIndex, y,
|
||||
lineHeight);
|
||||
|
||||
// Start position of the next line
|
||||
x = fLineInset;
|
||||
y += lineHeight + fLineSpacing;
|
||||
|
||||
if (lineBreak)
|
||||
lineStart = i + 1;
|
||||
else
|
||||
lineStart = i;
|
||||
|
||||
lineIndex++;
|
||||
}
|
||||
|
||||
if (!lineBreak && i < fGlyphInfoCount) {
|
||||
fGlyphInfoBuffer[i].x = x;
|
||||
fGlyphInfoBuffer[i].y = y;
|
||||
}
|
||||
|
||||
x += advanceX;
|
||||
y += advanceY;
|
||||
}
|
||||
|
||||
// The last line may not have been appended and initialized yet.
|
||||
if (lineStart <= fGlyphInfoCount - 1) {
|
||||
float lineHeight;
|
||||
_FinalizeLine(lineStart, fGlyphInfoCount - 1, lineIndex, y, lineHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::_GetGlyphAdvance(int offset, float& advanceX, float& advanceY,
|
||||
float escapementArray[]) const
|
||||
{
|
||||
float additionalGlyphSpacing = 0.0f;
|
||||
if (fGlyphInfoBuffer[offset].style.Get() != NULL)
|
||||
additionalGlyphSpacing = fGlyphInfoBuffer[offset].style->glyphSpacing;
|
||||
else
|
||||
additionalGlyphSpacing = fGlyphSpacing;
|
||||
|
||||
if (fGlyphInfoBuffer[offset].style.Get() != NULL
|
||||
&& fGlyphInfoBuffer[offset].style->width > 0.0f) {
|
||||
// Use the metrics provided by the TextStyle
|
||||
advanceX = fGlyphInfoBuffer[offset].style->width
|
||||
+ additionalGlyphSpacing;
|
||||
} else {
|
||||
advanceX = escapementArray[offset] + additionalGlyphSpacing;
|
||||
advanceY = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TextLayout::_FinalizeLine(int lineStart, int lineEnd, int lineIndex, float y,
|
||||
float& lineHeight)
|
||||
{
|
||||
printf("_FinalizeLine(%d, %d, %d, %.1f)\n", lineStart, lineEnd, lineIndex,
|
||||
y);
|
||||
lineHeight = 0.0f;
|
||||
float maxAscent = 0.0f;
|
||||
float maxDescent = 0.0f;
|
||||
|
||||
for (int i = lineStart; i <= lineEnd; i++) {
|
||||
if (fGlyphInfoBuffer[i].style.Get() != NULL) {
|
||||
if (fGlyphInfoBuffer[i].style->font.Size() > lineHeight)
|
||||
lineHeight = fGlyphInfoBuffer[i].style->font.Size();
|
||||
if (fGlyphInfoBuffer[i].style->ascent > maxAscent)
|
||||
maxAscent = fGlyphInfoBuffer[i].style->ascent;
|
||||
if (fGlyphInfoBuffer[i].style->descent > maxDescent)
|
||||
maxDescent = fGlyphInfoBuffer[i].style->descent;
|
||||
} else {
|
||||
if (fDefaultFont.Size() > lineHeight)
|
||||
lineHeight = fDefaultFont.Size();
|
||||
if (fAscent > maxAscent)
|
||||
maxAscent = fAscent;
|
||||
if (fDescent > maxDescent)
|
||||
maxDescent = fDescent;
|
||||
}
|
||||
}
|
||||
|
||||
fLineInfos.Add(LineInfo(lineStart, y, lineHeight, maxAscent, maxDescent));
|
||||
|
||||
for (int i = lineStart; i <= lineEnd; i++) {
|
||||
fGlyphInfoBuffer[i].maxAscend = maxAscent;
|
||||
fGlyphInfoBuffer[i].maxDescend = maxDescent;
|
||||
fGlyphInfoBuffer[i].lineIndex = lineIndex;
|
||||
fGlyphInfoBuffer[i].y += maxAscent;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,9 @@
|
||||
#include <Referenceable.h>
|
||||
#include <String.h>
|
||||
|
||||
#include "GlyphInfo.h"
|
||||
#include "LineInfo.h"
|
||||
|
||||
|
||||
class BView;
|
||||
|
||||
@ -27,6 +30,18 @@ public:
|
||||
const BFont& Font() const
|
||||
{ return fDefaultFont; }
|
||||
|
||||
void SetGlyphSpacing(float glyphSpacing);
|
||||
float GlyphSpacing() const
|
||||
{ return fGlyphSpacing; }
|
||||
|
||||
void SetFirstLineInset(float inset);
|
||||
float FirstLineInset() const
|
||||
{ return fFirstLineInset; }
|
||||
|
||||
void SetLineInset(float inset);
|
||||
float LineInset() const
|
||||
{ return fLineInset; }
|
||||
|
||||
void SetWidth(float width);
|
||||
float Width() const
|
||||
{ return fWidth; }
|
||||
@ -35,19 +50,32 @@ public:
|
||||
void Draw(BView* view, const BPoint& offset);
|
||||
|
||||
private:
|
||||
bool _ValidateLayout();
|
||||
|
||||
void _ValidateLayout();
|
||||
void _Layout();
|
||||
void _GetGlyphAdvance(int offset,
|
||||
float& advanceX, float& advanceY,
|
||||
float escapementArray[]) const;
|
||||
|
||||
void _FinalizeLine(int lineStart, int lineEnd,
|
||||
int lineIndex, float y, float& lineHeight);
|
||||
private:
|
||||
class Layout;
|
||||
friend class Layout;
|
||||
|
||||
BString fText;
|
||||
|
||||
BFont fDefaultFont;
|
||||
float fAscent;
|
||||
float fDescent;
|
||||
float fWidth;
|
||||
float fGlyphSpacing;
|
||||
float fFirstLineInset;
|
||||
float fLineInset;
|
||||
float fLineSpacing;
|
||||
|
||||
bool fLayoutValid;
|
||||
Layout* fLayout;
|
||||
|
||||
GlyphInfo* fGlyphInfoBuffer;
|
||||
int fGlyphInfoCount;
|
||||
LineInfoList fLineInfos;
|
||||
|
||||
};
|
||||
|
||||
#endif // FILTER_VIEW_H
|
||||
|
31
src/apps/haiku-depot/textview/TextStyle.cpp
Normal file
31
src/apps/haiku-depot/textview/TextStyle.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "TextStyle.h"
|
||||
|
||||
|
||||
TextStyle::TextStyle(const BFont& font, float ascent, float descent,
|
||||
float width, float glyphSpacing, rgb_color fgColor, rgb_color bgColor,
|
||||
bool strikeOut, rgb_color strikeOutColor, bool underline,
|
||||
uint32 underlineStyle, rgb_color underlineColor)
|
||||
:
|
||||
font(font),
|
||||
|
||||
ascent(ascent),
|
||||
descent(descent),
|
||||
width(width),
|
||||
glyphSpacing(glyphSpacing),
|
||||
|
||||
fgColor(fgColor),
|
||||
bgColor(bgColor),
|
||||
|
||||
strikeOut(strikeOut),
|
||||
strikeOutColor(strikeOutColor),
|
||||
|
||||
underline(underline),
|
||||
underlineStyle(underlineStyle),
|
||||
underlineColor(underlineColor)
|
||||
{
|
||||
}
|
45
src/apps/haiku-depot/textview/TextStyle.h
Normal file
45
src/apps/haiku-depot/textview/TextStyle.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef TEXT_STYLE_H
|
||||
#define TEXT_STYLE_H
|
||||
|
||||
#include <Font.h>
|
||||
#include <GraphicsDefs.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
|
||||
class TextStyle : public BReferenceable {
|
||||
public:
|
||||
TextStyle(const BFont& font, float ascent, float descent, float width,
|
||||
float glyphSpacing,
|
||||
rgb_color fgColor, rgb_color bgColor, bool strikeOut,
|
||||
rgb_color strikeOutColor, bool underline,
|
||||
uint32 underlineStyle, rgb_color underlineColor);
|
||||
|
||||
public:
|
||||
BFont font;
|
||||
|
||||
// The following three values override glyph metrics unless -1
|
||||
float ascent;
|
||||
float descent;
|
||||
float width;
|
||||
float glyphSpacing;
|
||||
|
||||
rgb_color fgColor;
|
||||
rgb_color bgColor;
|
||||
|
||||
bool strikeOut;
|
||||
rgb_color strikeOutColor;
|
||||
|
||||
bool underline;
|
||||
uint32 underlineStyle;
|
||||
rgb_color underlineColor;
|
||||
};
|
||||
|
||||
|
||||
typedef BReference<TextStyle> TextStyleRef;
|
||||
|
||||
|
||||
#endif // TEXT_STYLE_H
|
@ -36,21 +36,21 @@ TextView::FrameResized(float width, float height)
|
||||
BSize
|
||||
TextView::MinSize()
|
||||
{
|
||||
return BSize(fTextLayout.Width(), fTextLayout.Height());
|
||||
return BSize(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
BSize
|
||||
TextView::MaxSize()
|
||||
{
|
||||
return MinSize();
|
||||
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
|
||||
}
|
||||
|
||||
|
||||
BSize
|
||||
TextView::PreferredSize()
|
||||
{
|
||||
return MinSize();
|
||||
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
|
||||
}
|
||||
|
||||
|
||||
@ -62,8 +62,8 @@ TextView::HasHeightForWidth()
|
||||
|
||||
|
||||
void
|
||||
TextView::GetHeightForWidth(float width, float* min,
|
||||
float* max, float* preferred)
|
||||
TextView::GetHeightForWidth(float width, float* min, float* max,
|
||||
float* preferred)
|
||||
{
|
||||
TextLayout layout(fTextLayout);
|
||||
layout.SetWidth(width);
|
||||
|
@ -34,4 +34,4 @@ private:
|
||||
TextLayout fTextLayout;
|
||||
};
|
||||
|
||||
#endif // FILTER_VIEW_H
|
||||
#endif // TEXT_VIEW_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user