// 11 february 2017 #include "drawtext.h" static uiAttributedString *attrstr; static void setupAttributedString(void) { uiAttributeSpec spec; 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); spec.Type = uiAttributeFamily; spec.Value = (uintptr_t) "Courier New"; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "multiple sizes"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeSize; spec.Double = 18; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "multiple weights"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeWeight; spec.Value = (uintptr_t) uiDrawTextWeightBold; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "multiple italics"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeItalic; spec.Value = (uintptr_t) uiDrawTextItalicItalic; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "multiple stretches"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeStretch; spec.Value = (uintptr_t) uiDrawTextStretchCondensed; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "multiple colors"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeColor; // Direct2D "Crimson" (#DC143C) spec.R = 0.8627450980392156; spec.G = 0.0784313725490196; spec.B = 0.2352941176470588; spec.A = 0.75; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "multiple backgrounds"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeBackground; // Direct2D "Peach Puff" (#FFDAB9) // TODO choose a darker color spec.R = 1.0; spec.G = 0.85490196078431372; spec.B = 0.7254901960784313; spec.A = 0.5; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "vertical glyph forms"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeVerticalForms; spec.Value = 1; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, " (which you can draw rotated for proper vertical text)"); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "multiple"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeUnderline; spec.Value = uiDrawUnderlineStyleSingle; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, " "); next = "underlines"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeUnderline; spec.Value = uiDrawUnderlineStyleDouble; uiAttributedStringSetAttribute(attrstr, &spec, start, end); spec.Type = uiAttributeUnderlineColor; spec.Value = uiDrawUnderlineColorCustom; spec.R = 0.5; spec.G = 0.0; spec.B = 1.0; spec.A = 1.0; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, " ("); next = "including underlines for spelling correction and the like"; start = uiAttributedStringLen(attrstr); end = start + strlen(next); uiAttributedStringAppendUnattributed(attrstr, next); spec.Type = uiAttributeUnderline; spec.Value = uiDrawUnderlineStyleSuggestion; uiAttributedStringSetAttribute(attrstr, &spec, start, end); spec.Type = uiAttributeUnderlineColor; spec.Value = uiDrawUnderlineColorSpelling; uiAttributedStringSetAttribute(attrstr, &spec, start, end); uiAttributedStringAppendUnattributed(attrstr, ")"); uiAttributedStringAppendUnattributed(attrstr, ", "); next = "multiple TODO"; } 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; }