2017-02-10 15:29:36 -06:00
|
|
|
// 10 february 2017
|
|
|
|
#include "../ui.h"
|
|
|
|
#include "uipriv.h"
|
|
|
|
|
2017-02-24 20:18:15 -06:00
|
|
|
// TODO this doesn't handle the case where nLines == 0
|
|
|
|
// TODO this should never happen even if there are no characters??
|
2017-02-10 19:37:05 -06:00
|
|
|
// TODO figure out how to make this work on GTK+
|
2017-02-10 15:29:36 -06:00
|
|
|
void uiDrawCaret(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout, size_t pos, int *line)
|
|
|
|
{
|
|
|
|
double xoff;
|
|
|
|
uiDrawTextLayoutLineMetrics m;
|
|
|
|
struct caretDrawParams cdp;
|
|
|
|
uiDrawPath *path;
|
|
|
|
uiDrawBrush brush;
|
|
|
|
|
2017-02-10 18:29:07 -06:00
|
|
|
if (*line < 0)
|
|
|
|
*line = 0;
|
|
|
|
if (*line > (uiDrawTextLayoutNumLines(layout) - 1))
|
|
|
|
*line = (uiDrawTextLayoutNumLines(layout) - 1);
|
|
|
|
// TODO cap pos
|
2017-02-10 15:29:36 -06:00
|
|
|
xoff = uiDrawTextLayoutByteLocationInLine(layout, pos, *line);
|
2017-02-10 18:29:07 -06:00
|
|
|
while (xoff < 0) {
|
2017-02-10 15:29:36 -06:00
|
|
|
size_t start, end;
|
|
|
|
|
2017-02-10 18:29:07 -06:00
|
|
|
uiDrawTextLayoutLineByteRange(layout, *line, &start, &end);
|
|
|
|
if (end < pos) // too far up
|
|
|
|
(*line)++;
|
|
|
|
else
|
|
|
|
(*line)--;
|
|
|
|
xoff = uiDrawTextLayoutByteLocationInLine(layout, pos, *line);
|
2017-02-10 15:29:36 -06:00
|
|
|
}
|
|
|
|
uiDrawTextLayoutLineGetMetrics(layout, *line, &m);
|
|
|
|
|
2017-02-10 15:53:08 -06:00
|
|
|
caretDrawParams(c, m.Height, &cdp);
|
|
|
|
|
2017-02-10 15:29:36 -06:00
|
|
|
uiDrawSave(c);
|
|
|
|
|
|
|
|
path = uiDrawNewPath(uiDrawFillModeWinding);
|
|
|
|
uiDrawPathAddRectangle(path,
|
|
|
|
// TODO add m.X?
|
2017-02-10 15:53:08 -06:00
|
|
|
x + xoff - cdp.xoff, y + m.Y,
|
2017-02-10 15:29:36 -06:00
|
|
|
cdp.width, m.Height);
|
|
|
|
uiDrawPathEnd(path);
|
|
|
|
brush.Type = uiDrawBrushTypeSolid;
|
|
|
|
brush.R = cdp.r;
|
|
|
|
brush.G = cdp.g;
|
|
|
|
brush.B = cdp.b;
|
|
|
|
brush.A = cdp.a;
|
|
|
|
uiDrawFill(c, path, &brush);
|
|
|
|
uiDrawFreePath(path);
|
|
|
|
|
|
|
|
uiDrawRestore(c);
|
|
|
|
}
|
2017-02-13 00:22:59 -06:00
|
|
|
|
|
|
|
void drawTextBackground(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout, size_t start, size_t end, uiDrawBrush *brush, int isSelection)
|
|
|
|
{
|
|
|
|
int line, nLines;
|
|
|
|
size_t lstart, lend;
|
|
|
|
double layoutwid, layoutht;
|
|
|
|
|
|
|
|
uiDrawTextLayoutExtents(layout, &layoutwid, &layoutht);
|
|
|
|
nLines = uiDrawTextLayoutNumLines(layout);
|
|
|
|
for (line = 0; line < nLines; line++) {
|
|
|
|
uiDrawTextLayoutLineByteRange(layout, line, &lstart, &lend);
|
|
|
|
if (start >= lstart && start < lend)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
while (end - start > 0) {
|
|
|
|
uiDrawTextLayoutLineMetrics m;
|
|
|
|
double startx, endx;
|
|
|
|
uiDrawPath *path;
|
|
|
|
|
2017-02-13 01:10:39 -06:00
|
|
|
uiDrawTextLayoutLineByteRange(layout, line, &lstart, &lend);
|
2017-02-13 00:22:59 -06:00
|
|
|
if (lend > end) // don't cross lines
|
|
|
|
lend = end;
|
2017-02-13 01:10:39 -06:00
|
|
|
startx = uiDrawTextLayoutByteLocationInLine(layout, start, line);
|
2017-02-13 00:28:46 -06:00
|
|
|
// TODO explain this; note the use of start with lend
|
2017-02-13 00:22:59 -06:00
|
|
|
endx = layoutwid;
|
|
|
|
if (!isSelection || end <= lend)
|
2017-02-13 01:10:39 -06:00
|
|
|
endx = uiDrawTextLayoutByteLocationInLine(layout, lend, line);
|
2017-02-13 00:22:59 -06:00
|
|
|
uiDrawTextLayoutLineGetMetrics(layout, line, &m);
|
|
|
|
path = uiDrawNewPath(uiDrawFillModeWinding);
|
|
|
|
uiDrawPathAddRectangle(path,
|
|
|
|
x + startx, y + m.Y,
|
|
|
|
endx - startx, m.Height);
|
|
|
|
uiDrawPathEnd(path);
|
|
|
|
uiDrawFill(c, path, brush);
|
|
|
|
uiDrawFreePath(path);
|
|
|
|
line++;
|
2017-02-13 00:28:46 -06:00
|
|
|
start = lend;
|
2017-02-13 00:22:59 -06:00
|
|
|
}
|
|
|
|
}
|