2017-01-20 12:25:21 -06:00
|
|
|
// 17 january 2017
|
|
|
|
#include "drawtext.h"
|
|
|
|
|
|
|
|
static const char *text =
|
|
|
|
"It is with a kind of fear that I begin to write the history of my life. "
|
|
|
|
"I have, as it were, a superstitious hesitation in lifting the veil that "
|
|
|
|
"clings about my childhood like a golden mist. The task of writing an "
|
|
|
|
"autobiography is a difficult one. When I try to classify my earliest "
|
|
|
|
"impressions, I find that fact and fancy look alike across the years that "
|
|
|
|
"link the past with the present. The woman paints the child's experiences "
|
|
|
|
"in her own fantasy. A few impressions stand out vividly from the first "
|
|
|
|
"years of my life; but \"the shadows of the prison-house are on the rest.\" "
|
|
|
|
"Besides, many of the joys and sorrows of childhood have lost their "
|
|
|
|
"poignancy; and many incidents of vital importance in my early education "
|
|
|
|
"have been forgotten in the excitement of great discoveries. In order, "
|
|
|
|
"therefore, not to be tedious I shall try to present in a series of "
|
|
|
|
"sketches only the episodes that seem to me to be the most interesting "
|
|
|
|
"and important."
|
|
|
|
"";
|
|
|
|
static char fontFamily[] = "Palatino";
|
2017-02-11 18:47:20 -06:00
|
|
|
// TODO should be const; look at constructor function?
|
2017-01-20 12:25:21 -06:00
|
|
|
static uiDrawFontDescriptor defaultFont = {
|
|
|
|
.Family = fontFamily,
|
|
|
|
.Size = 18,
|
|
|
|
.Weight = uiDrawTextWeightNormal,
|
|
|
|
.Italic = uiDrawTextItalicNormal,
|
|
|
|
.Stretch = uiDrawTextStretchNormal,
|
|
|
|
};
|
|
|
|
static uiAttributedString *attrstr;
|
2017-02-11 18:47:20 -06:00
|
|
|
static uiDrawTextLayoutParams params;
|
2017-01-20 12:25:21 -06:00
|
|
|
|
|
|
|
#define margins 10
|
|
|
|
|
2017-01-20 15:36:44 -06:00
|
|
|
static uiBox *panel;
|
|
|
|
static uiCheckbox *showExtents;
|
|
|
|
static uiCheckbox *showLineBounds;
|
|
|
|
static uiCheckbox *showLineGuides;
|
|
|
|
|
|
|
|
// TODO should this be const?
|
|
|
|
static double strokeDashes[] = { 5, 2 };
|
|
|
|
// TODO this should be const
|
|
|
|
static uiDrawStrokeParams strokeParams = {
|
|
|
|
.Cap = uiDrawLineCapFlat,
|
|
|
|
.Join = uiDrawLineJoinMiter,
|
|
|
|
.Thickness = 1,
|
|
|
|
.MiterLimit = uiDrawDefaultMiterLimit,
|
|
|
|
.Dashes = strokeDashes,
|
|
|
|
.NumDashes = 2,
|
|
|
|
.DashPhase = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
// TODO come up with better colors
|
|
|
|
static uiDrawBrush strokeBrushes[3] = {
|
|
|
|
// baseline
|
|
|
|
{
|
|
|
|
.Type = uiDrawBrushTypeSolid,
|
|
|
|
.R = 0.5,
|
|
|
|
.G = 0.5,
|
|
|
|
.B = 0.0,
|
|
|
|
.A = 0.75,
|
|
|
|
},
|
|
|
|
// ascent
|
|
|
|
{
|
|
|
|
.Type = uiDrawBrushTypeSolid,
|
|
|
|
.R = 1.0,
|
|
|
|
.G = 0.0,
|
|
|
|
.B = 1.0,
|
|
|
|
.A = 0.75,
|
|
|
|
},
|
|
|
|
// descent
|
|
|
|
{
|
|
|
|
.Type = uiDrawBrushTypeSolid,
|
|
|
|
.R = 0.5,
|
|
|
|
.G = 0.75,
|
|
|
|
.B = 1.0,
|
|
|
|
.A = 0.75,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2017-01-20 12:25:21 -06:00
|
|
|
static void draw(uiAreaDrawParams *p)
|
|
|
|
{
|
|
|
|
uiDrawPath *path;
|
|
|
|
uiDrawTextLayout *layout;
|
2017-01-20 15:36:44 -06:00
|
|
|
uiDrawBrush b;
|
|
|
|
|
|
|
|
b.Type = uiDrawBrushTypeSolid;
|
|
|
|
|
|
|
|
// only clip the text, not the guides
|
|
|
|
uiDrawSave(p->Context);
|
2017-01-20 12:25:21 -06:00
|
|
|
|
|
|
|
path = uiDrawNewPath(uiDrawFillModeWinding);
|
|
|
|
uiDrawPathAddRectangle(path, margins, margins,
|
|
|
|
p->AreaWidth - 2 * margins,
|
|
|
|
p->AreaHeight - 2 * margins);
|
|
|
|
uiDrawPathEnd(path);
|
|
|
|
uiDrawClip(p->Context, path);
|
|
|
|
uiDrawFreePath(path);
|
|
|
|
|
|
|
|
// TODO get rid of this later
|
2017-01-20 15:36:44 -06:00
|
|
|
#if 0
|
2017-01-20 12:25:21 -06:00
|
|
|
path = uiDrawNewPath(uiDrawFillModeWinding);
|
|
|
|
uiDrawPathAddRectangle(path, -100, -100,
|
|
|
|
p->AreaWidth * 2,
|
|
|
|
p->AreaHeight * 2);
|
|
|
|
uiDrawPathEnd(path);
|
|
|
|
b.R = 0.0;
|
|
|
|
b.G = 1.0;
|
|
|
|
b.B = 0.0;
|
|
|
|
b.A = 1.0;
|
|
|
|
uiDrawFill(p->Context, path, &b);
|
|
|
|
uiDrawFreePath(path);
|
2017-01-20 15:36:44 -06:00
|
|
|
#endif
|
2017-01-20 12:25:21 -06:00
|
|
|
|
2017-02-11 18:47:20 -06:00
|
|
|
params.Width = p->AreaWidth - 2 * margins;
|
|
|
|
layout = uiDrawNewTextLayout(¶ms);
|
2017-01-20 12:25:21 -06:00
|
|
|
uiDrawText(p->Context, layout, margins, margins);
|
2017-01-20 15:36:44 -06:00
|
|
|
|
|
|
|
uiDrawRestore(p->Context);
|
|
|
|
|
|
|
|
if (uiCheckboxChecked(showExtents)) {
|
|
|
|
double width, height;
|
|
|
|
|
|
|
|
uiDrawTextLayoutExtents(layout, &width, &height);
|
|
|
|
path = uiDrawNewPath(uiDrawFillModeWinding);
|
|
|
|
uiDrawPathAddRectangle(path, margins, margins,
|
|
|
|
width, height);
|
|
|
|
uiDrawPathEnd(path);
|
|
|
|
b.R = 1.0;
|
|
|
|
b.G = 0.0;
|
|
|
|
b.B = 1.0;
|
|
|
|
b.A = 0.5;
|
|
|
|
uiDrawStroke(p->Context, path, &b, &strokeParams);
|
|
|
|
uiDrawFreePath(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uiCheckboxChecked(showLineBounds) || uiCheckboxChecked(showLineGuides)) {
|
|
|
|
uiDrawTextLayoutLineMetrics m;
|
|
|
|
int i, n;
|
|
|
|
int fill = 0;
|
|
|
|
|
|
|
|
n = uiDrawTextLayoutNumLines(layout);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
uiDrawTextLayoutLineGetMetrics(layout, i, &m);
|
|
|
|
|
|
|
|
if (uiCheckboxChecked(showLineBounds)) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
if (uiCheckboxChecked(showLineGuides)) {
|
|
|
|
// baseline
|
|
|
|
path = uiDrawNewPath(uiDrawFillModeWinding);
|
|
|
|
uiDrawPathNewFigure(path,
|
|
|
|
margins + m.X,
|
|
|
|
margins + m.BaselineY);
|
|
|
|
uiDrawPathLineTo(path,
|
|
|
|
margins + m.X + m.Width,
|
|
|
|
margins + m.BaselineY);
|
|
|
|
uiDrawPathEnd(path);
|
|
|
|
uiDrawStroke(p->Context, path, &(strokeBrushes[0]), &strokeParams);
|
|
|
|
uiDrawFreePath(path);
|
|
|
|
|
|
|
|
// ascent line
|
|
|
|
path = uiDrawNewPath(uiDrawFillModeWinding);
|
|
|
|
uiDrawPathNewFigure(path,
|
|
|
|
margins + m.X,
|
|
|
|
margins + m.BaselineY - m.Ascent);
|
|
|
|
uiDrawPathLineTo(path,
|
|
|
|
margins + m.X + m.Width,
|
|
|
|
margins + m.BaselineY - m.Ascent);
|
|
|
|
uiDrawPathEnd(path);
|
|
|
|
uiDrawStroke(p->Context, path, &(strokeBrushes[1]), &strokeParams);
|
|
|
|
uiDrawFreePath(path);
|
|
|
|
|
|
|
|
// descent line
|
|
|
|
path = uiDrawNewPath(uiDrawFillModeWinding);
|
|
|
|
uiDrawPathNewFigure(path,
|
|
|
|
margins + m.X,
|
|
|
|
margins + m.BaselineY + m.Descent);
|
|
|
|
uiDrawPathLineTo(path,
|
|
|
|
margins + m.X + m.Width,
|
|
|
|
margins + m.BaselineY + m.Descent);
|
|
|
|
uiDrawPathEnd(path);
|
|
|
|
uiDrawStroke(p->Context, path, &(strokeBrushes[2]), &strokeParams);
|
|
|
|
uiDrawFreePath(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-20 12:25:21 -06:00
|
|
|
uiDrawFreeTextLayout(layout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct example basicExample;
|
|
|
|
|
2017-01-20 15:36:44 -06:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2017-01-20 12:25:21 -06:00
|
|
|
struct example *mkBasicExample(void)
|
|
|
|
{
|
2017-01-20 15:36:44 -06:00
|
|
|
panel = uiNewVerticalBox();
|
|
|
|
showExtents = newCheckbox("Show Layout Extents");
|
|
|
|
showLineBounds = newCheckbox("Show Line Bounds");
|
|
|
|
showLineGuides = newCheckbox("Show Line Guides");
|
|
|
|
|
2017-01-20 12:25:21 -06:00
|
|
|
basicExample.name = "Basic Paragraph of Text";
|
2017-01-20 15:36:44 -06:00
|
|
|
basicExample.panel = uiControl(panel);
|
2017-01-20 12:25:21 -06:00
|
|
|
basicExample.draw = draw;
|
2017-02-05 23:26:22 -06:00
|
|
|
basicExample.mouse = NULL;
|
2017-02-10 18:22:25 -06:00
|
|
|
basicExample.key = NULL;
|
2017-01-20 12:25:21 -06:00
|
|
|
|
|
|
|
attrstr = uiNewAttributedString(text);
|
2017-02-11 18:47:20 -06:00
|
|
|
params.String = attrstr;
|
|
|
|
params.DefaultFont = &defaultFont;
|
2017-06-06 13:14:33 -05:00
|
|
|
params.Align = uiDrawTextAlignLeft;
|
2017-01-20 12:25:21 -06:00
|
|
|
|
|
|
|
return &basicExample;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO on GTK+ an area by itself in a window doesn't get expand properties set properly?
|