Added a test for making uiDrawTextLayouts on empty strings. We're already off to a good start since we have a ~0 error on OS X...
This commit is contained in:
parent
5fe4e27c5d
commit
5234586ead
|
@ -34,6 +34,7 @@ endif()
|
|||
_add_example(drawtext
|
||||
drawtext/attributes.c
|
||||
drawtext/basic.c
|
||||
drawtext/emptystr_hittest.c
|
||||
drawtext/hittest.c
|
||||
drawtext/main.c
|
||||
${_EXAMPLE_RESOURCES_RC}
|
||||
|
|
|
@ -23,3 +23,6 @@ extern struct example *mkHitTestExample(void);
|
|||
|
||||
// attributes.c
|
||||
extern struct example *mkAttributesExample(void);
|
||||
|
||||
// emptystr_hittest.c
|
||||
extern struct example *mkEmptyStringExample(void);
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
// 20 january 2017
|
||||
#include "drawtext.h"
|
||||
|
||||
// TODO FOR THIS FILE
|
||||
// get rid of it once we rewrite this example (which requires having more fine-grained scrolling control)
|
||||
|
||||
// TODO double-check ligatures on all platforms to make sure we can place the cursor at the right place
|
||||
// TODO the hiding and showing does not work properly on GTK+
|
||||
// TODO using the arrow keys allows us to walk back to the end of the line on some platforms (TODO which?); IIRC arrow keys shouldn't do that
|
||||
// TODO make sure to check the cursor positions of RTL on all platforms
|
||||
|
||||
static const char *text = "";
|
||||
static char fontFamily[] = "Helvetica";
|
||||
static uiDrawFontDescriptor defaultFont = {
|
||||
.Family = fontFamily,
|
||||
.Size = 14,
|
||||
.Weight = uiDrawTextWeightNormal,
|
||||
.Italic = uiDrawTextItalicNormal,
|
||||
.Stretch = uiDrawTextStretchNormal,
|
||||
};
|
||||
static uiAttributedString *attrstr;
|
||||
static uiDrawTextLayoutParams params;
|
||||
|
||||
#define margins 10
|
||||
|
||||
static uiBox *panel;
|
||||
static uiBox *vbox;
|
||||
static uiLabel *caretLabel;
|
||||
static uiCheckbox *showLineBounds;
|
||||
static uiFontButton *fontButton;
|
||||
static uiCombobox *textAlign;
|
||||
|
||||
static int caretLine = -1;
|
||||
static size_t caretPos;
|
||||
|
||||
// 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;
|
||||
uiDrawTextLayoutLineMetrics m;
|
||||
|
||||
// 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 (caretLine == -1) {
|
||||
caretLine = uiDrawTextLayoutNumLines(layout) - 1;
|
||||
caretPos = uiAttributedStringLen(attrstr);
|
||||
}
|
||||
uiDrawCaret(p->Context, margins, margins,
|
||||
layout, caretPos, &caretLine);
|
||||
|
||||
if (uiCheckboxChecked(showLineBounds)) {
|
||||
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 void mouse(uiAreaMouseEvent *e)
|
||||
{
|
||||
uiDrawTextLayout *layout;
|
||||
char labelText[128];
|
||||
|
||||
if (e->Down != 1)
|
||||
return;
|
||||
|
||||
params.Width = e->AreaWidth - 2 * margins;
|
||||
layout = uiDrawNewTextLayout(¶ms);
|
||||
uiDrawTextLayoutHitTest(layout,
|
||||
e->X - margins, e->Y - margins,
|
||||
&caretPos, &caretLine);
|
||||
uiDrawFreeTextLayout(layout);
|
||||
|
||||
// TODO move this into the draw handler so it is reflected by keyboard-based position changes
|
||||
// urgh %zd is not supported by MSVC with sprintf()
|
||||
// TODO get that part in test/ about having no other option
|
||||
sprintf(labelText, "pos %d line %d",
|
||||
(int) caretPos, caretLine);
|
||||
uiLabelSetText(caretLabel, labelText);
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
static int key(uiAreaKeyEvent *e)
|
||||
{
|
||||
size_t grapheme;
|
||||
|
||||
if (e->Up)
|
||||
return 0;
|
||||
if (e->Key != 0)
|
||||
return 0;
|
||||
switch (e->ExtKey) {
|
||||
case uiExtKeyUp:
|
||||
// TODO
|
||||
return 1;
|
||||
case uiExtKeyDown:
|
||||
// TODO
|
||||
return 1;
|
||||
case uiExtKeyLeft:
|
||||
grapheme = uiAttributedStringByteIndexToGrapheme(attrstr, caretPos);
|
||||
if (grapheme == 0)
|
||||
return 0;
|
||||
grapheme--;
|
||||
caretPos = uiAttributedStringGraphemeToByteIndex(attrstr, grapheme);
|
||||
redraw();
|
||||
return 1;
|
||||
case uiExtKeyRight:
|
||||
grapheme = uiAttributedStringByteIndexToGrapheme(attrstr, caretPos);
|
||||
if (grapheme == uiAttributedStringNumGraphemes(attrstr))
|
||||
return 0;
|
||||
grapheme++;
|
||||
caretPos = uiAttributedStringGraphemeToByteIndex(attrstr, grapheme);
|
||||
redraw();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct example hitTestExample;
|
||||
|
||||
// TODO share?
|
||||
static void checkboxChecked(uiCheckbox *c, void *data)
|
||||
{
|
||||
redraw();
|
||||
}
|
||||
|
||||
static void changeFont(uiFontButton *b, void *data)
|
||||
{
|
||||
if (defaultFont.Family != fontFamily)
|
||||
uiFreeText(defaultFont.Family);
|
||||
// TODO rename defaultFont
|
||||
uiFontButtonFont(fontButton, &defaultFont);
|
||||
printf("{\n\tfamily: %s\n\tsize: %g\n\tweight: %d\n\titalic: %d\n\tstretch: %d\n}\n",
|
||||
defaultFont.Family,
|
||||
defaultFont.Size,
|
||||
(int) (defaultFont.Weight),
|
||||
(int) (defaultFont.Italic),
|
||||
(int) (defaultFont.Stretch));
|
||||
redraw();
|
||||
}
|
||||
|
||||
static void changeTextAlign(uiCombobox *c, void *data)
|
||||
{
|
||||
// note the order of the items added below
|
||||
params.Align = (uiDrawTextLayoutAlign) uiComboboxSelected(textAlign);
|
||||
redraw();
|
||||
}
|
||||
|
||||
// TODO share?
|
||||
static uiCheckbox *newCheckbox(uiBox *box, const char *text)
|
||||
{
|
||||
uiCheckbox *c;
|
||||
|
||||
c = uiNewCheckbox(text);
|
||||
uiCheckboxOnToggled(c, checkboxChecked, NULL);
|
||||
uiBoxAppend(box, uiControl(c), 0);
|
||||
return c;
|
||||
}
|
||||
|
||||
struct example *mkEmptyStringExample(void)
|
||||
{
|
||||
panel = uiNewHorizontalBox();
|
||||
vbox = uiNewVerticalBox();
|
||||
// TODO the second vbox causes this not to stretch at least on OS X
|
||||
uiBoxAppend(panel, uiControl(vbox), 1);
|
||||
caretLabel = uiNewLabel("Caret information is shown here");
|
||||
uiBoxAppend(vbox, uiControl(caretLabel), 0);
|
||||
showLineBounds = newCheckbox(vbox, "Show Line Bounds (for debugging metrics)");
|
||||
vbox = uiNewVerticalBox();
|
||||
uiBoxAppend(panel, uiControl(vbox), 0);
|
||||
fontButton = uiNewFontButton();
|
||||
uiFontButtonOnChanged(fontButton, changeFont, NULL);
|
||||
// TODO set the font button to the current defaultFont
|
||||
uiBoxAppend(vbox, uiControl(fontButton), 0);
|
||||
textAlign = uiNewCombobox();
|
||||
// note that these are in the order in the enum
|
||||
uiComboboxAppend(textAlign, "Left");
|
||||
uiComboboxAppend(textAlign, "Center");
|
||||
uiComboboxAppend(textAlign, "Right");
|
||||
uiComboboxOnSelected(textAlign, changeTextAlign, NULL);
|
||||
uiBoxAppend(vbox, uiControl(textAlign), 0);
|
||||
|
||||
hitTestExample.name = "Empty String";
|
||||
hitTestExample.panel = uiControl(panel);
|
||||
hitTestExample.draw = draw;
|
||||
hitTestExample.mouse = mouse;
|
||||
hitTestExample.key = key;
|
||||
|
||||
attrstr = uiNewAttributedString(text);
|
||||
params.String = attrstr;
|
||||
params.DefaultFont = &defaultFont;
|
||||
params.Align = uiDrawTextLayoutAlignLeft;
|
||||
|
||||
return &hitTestExample;
|
||||
}
|
|
@ -115,6 +115,11 @@ int main(void)
|
|||
uiControlHide(examples[n]->panel);
|
||||
uiBoxAppend(box, examples[n]->panel, 0);
|
||||
n++;
|
||||
examples[n] = mkEmptyStringExample();
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue