From 32a0284edcb3bedfd31f19d9184ac06137611a3b Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 11 Feb 2017 23:19:30 -0500 Subject: [PATCH] Started work on actual attributed text. This includes the beginnings of an attributed text example. Now to implement. --- common/attrstr.c | 5 ++ examples/CMakeLists.txt | 1 + examples/drawtext/attributes.c | 159 +++++++++++++++++++++++++++++++++ examples/drawtext/drawtext.h | 3 + examples/drawtext/main.c | 5 ++ ui_attrstr.h | 11 ++- 6 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 examples/drawtext/attributes.c diff --git a/common/attrstr.c b/common/attrstr.c index f62c42f2..93e4e8f4 100644 --- a/common/attrstr.c +++ b/common/attrstr.c @@ -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) { diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 3fda1b82..64c7098c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -32,6 +32,7 @@ if(NOT WIN32) endif() _add_example(drawtext + drawtext/attributes.c drawtext/basic.c drawtext/hittest.c drawtext/main.c diff --git a/examples/drawtext/attributes.c b/examples/drawtext/attributes.c new file mode 100644 index 00000000..b66635df --- /dev/null +++ b/examples/drawtext/attributes.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; +} diff --git a/examples/drawtext/drawtext.h b/examples/drawtext/drawtext.h index f14ee485..0ac4cb36 100644 --- a/examples/drawtext/drawtext.h +++ b/examples/drawtext/drawtext.h @@ -20,3 +20,6 @@ extern struct example *mkBasicExample(void); // hittest.c extern struct example *mkHitTestExample(void); + +// attributes.c +extern struct example *mkAttributesExample(void); diff --git a/examples/drawtext/main.c b/examples/drawtext/main.c index cc28acd3..822382d0 100644 --- a/examples/drawtext/main.c +++ b/examples/drawtext/main.c @@ -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); diff --git a/ui_attrstr.h b/ui_attrstr.h index 63aed4c0..87eac1cf 100644 --- a/ui_attrstr.h +++ b/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;