Started work on actual attributed text. This includes the beginnings of an attributed text example. Now to implement.
This commit is contained in:
parent
c4a97792ea
commit
32a0284edc
|
@ -297,6 +297,11 @@ size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t pos)
|
|||
return pos;
|
||||
}
|
||||
|
||||
void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttribute type, uintptr_t value, size_t start, size_t end)
|
||||
{
|
||||
attrlistInsertAttribute(s->attrs, type, value, start, end);
|
||||
}
|
||||
|
||||
// TODO introduce an iterator?
|
||||
void uiAttributedStringForEachAttribute(uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data)
|
||||
{
|
||||
|
|
|
@ -32,6 +32,7 @@ if(NOT WIN32)
|
|||
endif()
|
||||
|
||||
_add_example(drawtext
|
||||
drawtext/attributes.c
|
||||
drawtext/basic.c
|
||||
drawtext/hittest.c
|
||||
drawtext/main.c
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
// 11 february 2017
|
||||
#include "drawtext.h"
|
||||
|
||||
static uiAttributedString *attrstr;
|
||||
|
||||
static void setupAttributedString(void)
|
||||
{
|
||||
size_t start, end;
|
||||
const char *next;
|
||||
|
||||
attrstr = uiNewAttributedString("uiAttributedString isn't just for plain text! It supports ");
|
||||
|
||||
next = "multiple fonts";
|
||||
start = uiAttributedStringLen(attrstr);
|
||||
end = start + strlen(next);
|
||||
uiAttributedStringAppendUnattributed(attrstr, next);
|
||||
uiAttributedStringSetAttribute(attrstr,
|
||||
uiAttributeFamily,
|
||||
(uintptr_t) "Courier New",
|
||||
start, end);
|
||||
|
||||
uiAttributedStringAppendUnattributed(attrstr, ", ");
|
||||
|
||||
next = "multiple sizes";
|
||||
}
|
||||
|
||||
static char fontFamily[] = "Times New Roman";
|
||||
// TODO should be const; look at constructor function?
|
||||
static uiDrawFontDescriptor defaultFont = {
|
||||
.Family = fontFamily,
|
||||
.Size = 12,
|
||||
.Weight = uiDrawTextWeightNormal,
|
||||
.Italic = uiDrawTextItalicNormal,
|
||||
.Stretch = uiDrawTextStretchNormal,
|
||||
};
|
||||
static uiDrawTextLayoutParams params;
|
||||
|
||||
#define margins 10
|
||||
|
||||
static uiBox *panel;
|
||||
static uiCheckbox *showExtents;
|
||||
static uiCheckbox *showLineBounds;
|
||||
static uiCheckbox *showLineGuides;
|
||||
|
||||
// TODO should be const?
|
||||
static uiDrawBrush fillBrushes[4] = {
|
||||
{
|
||||
.Type = uiDrawBrushTypeSolid,
|
||||
.R = 1.0,
|
||||
.G = 0.0,
|
||||
.B = 0.0,
|
||||
.A = 0.5,
|
||||
},
|
||||
{
|
||||
.Type = uiDrawBrushTypeSolid,
|
||||
.R = 0.0,
|
||||
.G = 1.0,
|
||||
.B = 0.0,
|
||||
.A = 0.5,
|
||||
},
|
||||
{
|
||||
.Type = uiDrawBrushTypeSolid,
|
||||
.R = 0.0,
|
||||
.G = 0.0,
|
||||
.B = 1.0,
|
||||
.A = 0.5,
|
||||
},
|
||||
{
|
||||
.Type = uiDrawBrushTypeSolid,
|
||||
.R = 0.0,
|
||||
.G = 1.0,
|
||||
.B = 1.0,
|
||||
.A = 0.5,
|
||||
},
|
||||
};
|
||||
|
||||
static void draw(uiAreaDrawParams *p)
|
||||
{
|
||||
uiDrawPath *path;
|
||||
uiDrawTextLayout *layout;
|
||||
uiDrawBrush b;
|
||||
|
||||
b.Type = uiDrawBrushTypeSolid;
|
||||
|
||||
// only clip the text, not the guides
|
||||
uiDrawSave(p->Context);
|
||||
|
||||
path = uiDrawNewPath(uiDrawFillModeWinding);
|
||||
uiDrawPathAddRectangle(path, margins, margins,
|
||||
p->AreaWidth - 2 * margins,
|
||||
p->AreaHeight - 2 * margins);
|
||||
uiDrawPathEnd(path);
|
||||
uiDrawClip(p->Context, path);
|
||||
uiDrawFreePath(path);
|
||||
|
||||
params.Width = p->AreaWidth - 2 * margins;
|
||||
layout = uiDrawNewTextLayout(¶ms);
|
||||
uiDrawText(p->Context, layout, margins, margins);
|
||||
|
||||
uiDrawRestore(p->Context);
|
||||
|
||||
if (uiCheckboxChecked(showLineBounds)) {
|
||||
uiDrawTextLayoutLineMetrics m;
|
||||
int i, n;
|
||||
int fill = 0;
|
||||
|
||||
n = uiDrawTextLayoutNumLines(layout);
|
||||
for (i = 0; i < n; i++) {
|
||||
uiDrawTextLayoutLineGetMetrics(layout, i, &m);
|
||||
|
||||
path = uiDrawNewPath(uiDrawFillModeWinding);
|
||||
uiDrawPathAddRectangle(path, margins + m.X, margins + m.Y,
|
||||
m.Width, m.Height);
|
||||
uiDrawPathEnd(path);
|
||||
uiDrawFill(p->Context, path, fillBrushes + fill);
|
||||
uiDrawFreePath(path);
|
||||
fill = (fill + 1) % 4;
|
||||
}
|
||||
}
|
||||
|
||||
uiDrawFreeTextLayout(layout);
|
||||
}
|
||||
|
||||
static struct example attributesExample;
|
||||
|
||||
// TODO share?
|
||||
static void checkboxChecked(uiCheckbox *c, void *data)
|
||||
{
|
||||
redraw();
|
||||
}
|
||||
|
||||
static uiCheckbox *newCheckbox(const char *text)
|
||||
{
|
||||
uiCheckbox *c;
|
||||
|
||||
c = uiNewCheckbox(text);
|
||||
uiCheckboxOnToggled(c, checkboxChecked, NULL);
|
||||
uiBoxAppend(panel, uiControl(c), 0);
|
||||
return c;
|
||||
}
|
||||
|
||||
struct example *mkAttributesExample(void)
|
||||
{
|
||||
panel = uiNewVerticalBox();
|
||||
showLineBounds = newCheckbox("Show Line Bounds");
|
||||
|
||||
attributesExample.name = "Attributed Text";
|
||||
attributesExample.panel = uiControl(panel);
|
||||
attributesExample.draw = draw;
|
||||
attributesExample.mouse = NULL;
|
||||
attributesExample.key = NULL;
|
||||
|
||||
setupAttributedString();
|
||||
params.String = attrstr;
|
||||
params.DefaultFont = &defaultFont;
|
||||
params.Align = uiDrawTextLayoutAlignLeft;
|
||||
|
||||
return &attributesExample;
|
||||
}
|
|
@ -20,3 +20,6 @@ extern struct example *mkBasicExample(void);
|
|||
|
||||
// hittest.c
|
||||
extern struct example *mkHitTestExample(void);
|
||||
|
||||
// attributes.c
|
||||
extern struct example *mkAttributesExample(void);
|
||||
|
|
|
@ -110,6 +110,11 @@ int main(void)
|
|||
uiControlHide(examples[n]->panel);
|
||||
uiBoxAppend(box, examples[n]->panel, 0);
|
||||
n++;
|
||||
examples[n] = mkAttributesExample();
|
||||
uiComboboxAppend(exampleList, examples[n]->name);
|
||||
uiControlHide(examples[n]->panel);
|
||||
uiBoxAppend(box, examples[n]->panel, 0);
|
||||
n++;
|
||||
// and set things up for the initial state
|
||||
uiComboboxSetSelected(exampleList, 0);
|
||||
uiComboboxOnSelected(exampleList, onExampleChanged, NULL);
|
||||
|
|
11
ui_attrstr.h
11
ui_attrstr.h
|
@ -1,15 +1,19 @@
|
|||
typedef struct uiAttributedString uiAttributedString;
|
||||
|
||||
_UI_ENUM(uiAttribute) {
|
||||
// TODO uiAttributeFamily,
|
||||
// TODO uiAttributeSize,
|
||||
// TODO once we allow loading fonts in memory we can't use just one pointer anymore
|
||||
uiAttributeFamily,
|
||||
// TODO no guarantee this can fit in a uintptr_t; we need a better way to store these...
|
||||
uiAttributeSize,
|
||||
uiAttributeWeight,
|
||||
uiAttributeItalic,
|
||||
uiAttributeStretch,
|
||||
// TODO
|
||||
// TODO uiAttributeSystem,
|
||||
// TODO uiAttributeCustom,
|
||||
};
|
||||
|
||||
typedef int (*uiAttributedStringForEachAttributeFunc)(uiAttributedString *, uiAttribute type, uintptr_t value, size_t start, size_t end, void *data);
|
||||
typedef int (*uiAttributedStringForEachAttributeFunc)(uiAttributedString *s, uiAttribute type, uintptr_t value, size_t start, size_t end, void *data);
|
||||
|
||||
// @role uiAttributedString constructor
|
||||
// uiNewAttributedString() creates a new uiAttributedString from
|
||||
|
@ -35,6 +39,7 @@ _UI_EXTERN void uiAttributedStringDelete(uiAttributedString *s, size_t start, si
|
|||
_UI_EXTERN size_t uiAttributedStringNumGraphemes(uiAttributedString *s);
|
||||
_UI_EXTERN size_t uiAttributedStringByteIndexToGrapheme(uiAttributedString *s, size_t pos);
|
||||
_UI_EXTERN size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t pos);
|
||||
_UI_EXTERN void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttribute type, uintptr_t value, size_t start, size_t end);
|
||||
_UI_EXTERN void uiAttributedStringForEachAttribute(uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data);
|
||||
|
||||
typedef struct uiDrawFontDescriptor uiDrawFontDescriptor;
|
||||
|
|
Loading…
Reference in New Issue