First Commit

This commit is contained in:
dsutanto committed 2025-11-19 16:30:37 +07:00
commit ae0fab9400
424 files changed
+71006

No files matched your search

+22
View File
@@ -0,0 +1,22 @@
// 21 june 2016
#include "../ui.h"
#include "uipriv.h"
void *uiTableModelGiveInt(int i)
{
return (void *) ((intptr_t) i);
}
int uiTableModelTakeInt(void *v)
{
return (int) ((intptr_t) v);
}
uiTableColumn *uiTableAppendTextColumn(uiTable *t, const char *name, int modelColumn)
{
uiTableColumn *tc;
tc = uiTableAppendColumn(t, name);
uiTableColumnAppendTextPart(tc, modelColumn, 1);
return tc;
}
+169
View File
@@ -0,0 +1,169 @@
// 29 march 2014
#include "../ui.h"
#include "uipriv.h"
/*
Windows and GTK+ have a limit of 2 and 3 clicks, respectively, natively supported. Fortunately, we can simulate the double/triple-click behavior to build higher-order clicks. We can use the same algorithm Windows uses on both:
http://blogs.msdn.com/b/oldnewthing/archive/2004/10/18/243925.aspx
For GTK+, we pull the double-click time and double-click distance, which work the same as the equivalents on Windows (so the distance is in all directions), from the GtkSettings system.
On GTK+ this will also allow us to discard the GDK_BUTTON_2PRESS and GDK_BUTTON_3PRESS events, so the button press stream will be just like on other platforms.
Thanks to mclasen, garnacho_, halfline, and tristan in irc.gimp.net/#gtk+.
TODO note the bits about asymmetry and g_rcClick initial value not mattering in the oldnewthing article
*/
// x, y, xdist, ydist, and c.rect must have the same units
// so must time, maxTime, and c.prevTime
int uiprivClickCounterClick(uiprivClickCounter *c, int button, int x, int y, uintptr_t time, uintptr_t maxTime, int32_t xdist, int32_t ydist)
{
// different button than before? if so, don't count
if (button != c->curButton)
c->count = 0;
// (x, y) in the allowed region for a double-click? if not, don't count
if (x < c->rectX0)
c->count = 0;
if (y < c->rectY0)
c->count = 0;
if (x >= c->rectX1)
c->count = 0;
if (y >= c->rectY1)
c->count = 0;
// too slow? if so, don't count
// note the below expression; time > (c.prevTime + maxTime) can overflow!
if ((time - c->prevTime) > maxTime) // too slow; don't count
c->count = 0;
c->count++; // if either of the above ifs happened, this will make the click count 1; otherwise it will make the click count 2, 3, 4, 5, ...
// now we need to update the internal structures for the next test
c->curButton = button;
c->prevTime = time;
c->rectX0 = x - xdist;
c->rectY0 = y - ydist;
c->rectX1 = x + xdist;
c->rectY1 = y + ydist;
return c->count;
}
void uiprivClickCounterReset(uiprivClickCounter *c)
{
c->curButton = 0;
c->rectX0 = 0;
c->rectY0 = 0;
c->rectX1 = 0;
c->rectY1 = 0;
c->prevTime = 0;
c->count = 0;
}
/*
For position independence across international keyboard layouts, typewriter keys are read using scancodes (which are always set 1).
Windows provides the scancodes directly in the LPARAM.
GTK+ provides the scancodes directly from the underlying window system via GdkEventKey.hardware_keycode.
On X11, this is scancode + 8 (because X11 keyboard codes have a range of [8,255]).
Wayland is guaranteed to give the same result (thanks ebassi in irc.gimp.net/#gtk+).
On Linux, where evdev is used instead of polling scancodes directly from the keyboard, evdev's typewriter section key code constants are the same as scancodes anyway, so the rules above apply.
Typewriter section scancodes are the same across international keyboards with some exceptions that have been accounted for (see KeyEvent's documentation); see http://www.quadibloc.com/comp/scan.htm for details.
Non-typewriter keys can be handled safely using constants provided by the respective backend API.
Because GTK+ keysyms may or may not obey Num Lock, we also handle the 0-9 and . keys on the numeric keypad with scancodes (they match too).
*/
// use uintptr_t to be safe; the size of the scancode/hardware key code field on each platform is different
static const struct {
uintptr_t scancode;
char equiv;
} scancodeKeys[] = {
{ 0x02, '1' },
{ 0x03, '2' },
{ 0x04, '3' },
{ 0x05, '4' },
{ 0x06, '5' },
{ 0x07, '6' },
{ 0x08, '7' },
{ 0x09, '8' },
{ 0x0A, '9' },
{ 0x0B, '0' },
{ 0x0C, '-' },
{ 0x0D, '=' },
{ 0x0E, '\b' },
{ 0x0F, '\t' },
{ 0x10, 'q' },
{ 0x11, 'w' },
{ 0x12, 'e' },
{ 0x13, 'r' },
{ 0x14, 't' },
{ 0x15, 'y' },
{ 0x16, 'u' },
{ 0x17, 'i' },
{ 0x18, 'o' },
{ 0x19, 'p' },
{ 0x1A, '[' },
{ 0x1B, ']' },
{ 0x1C, '\n' },
{ 0x1E, 'a' },
{ 0x1F, 's' },
{ 0x20, 'd' },
{ 0x21, 'f' },
{ 0x22, 'g' },
{ 0x23, 'h' },
{ 0x24, 'j' },
{ 0x25, 'k' },
{ 0x26, 'l' },
{ 0x27, ';' },
{ 0x28, '\'' },
{ 0x29, '`' },
{ 0x2B, '\\' },
{ 0x2C, 'z' },
{ 0x2D, 'x' },
{ 0x2E, 'c' },
{ 0x2F, 'v' },
{ 0x30, 'b' },
{ 0x31, 'n' },
{ 0x32, 'm' },
{ 0x33, ',' },
{ 0x34, '.' },
{ 0x35, '/' },
{ 0x39, ' ' },
{ 0xFFFF, 0 },
};
static const struct {
uintptr_t scancode;
uiExtKey equiv;
} scancodeExtKeys[] = {
{ 0x47, uiExtKeyN7 },
{ 0x48, uiExtKeyN8 },
{ 0x49, uiExtKeyN9 },
{ 0x4B, uiExtKeyN4 },
{ 0x4C, uiExtKeyN5 },
{ 0x4D, uiExtKeyN6 },
{ 0x4F, uiExtKeyN1 },
{ 0x50, uiExtKeyN2 },
{ 0x51, uiExtKeyN3 },
{ 0x52, uiExtKeyN0 },
{ 0x53, uiExtKeyNDot },
{ 0xFFFF, 0 },
};
int uiprivFromScancode(uintptr_t scancode, uiAreaKeyEvent *ke)
{
int i;
for (i = 0; scancodeKeys[i].scancode != 0xFFFF; i++)
if (scancodeKeys[i].scancode == scancode) {
ke->Key = scancodeKeys[i].equiv;
return 1;
}
for (i = 0; scancodeExtKeys[i].scancode != 0xFFFF; i++)
if (scancodeExtKeys[i].scancode == scancode) {
ke->ExtKey = scancodeExtKeys[i].equiv;
return 1;
}
return 0;
}
+266
View File
@@ -0,0 +1,266 @@
// 19 february 2018
#include "../ui.h"
#include "uipriv.h"
#include "attrstr.h"
struct uiAttribute {
int ownedByUser;
size_t refcount;
uiAttributeType type;
union {
char *family;
double size;
uiTextWeight weight;
uiTextItalic italic;
uiTextStretch stretch;
struct {
double r;
double g;
double b;
double a;
// put this here so we can reuse this structure
uiUnderlineColor underlineColor;
} color;
uiUnderline underline;
uiOpenTypeFeatures *features;
} u;
};
static uiAttribute *newAttribute(uiAttributeType type)
{
uiAttribute *a;
a = uiprivNew(uiAttribute);
a->ownedByUser = 1;
a->refcount = 0;
a->type = type;
return a;
}
// returns a to allow expressions like b = uiprivAttributeRetain(a)
// TODO would this allow us to copy attributes between strings in a foreach func, and if so, should that be allowed?
uiAttribute *uiprivAttributeRetain(uiAttribute *a)
{
a->ownedByUser = 0;
a->refcount++;
return a;
}
static void destroy(uiAttribute *a)
{
switch (a->type) {
case uiAttributeTypeFamily:
uiprivFree(a->u.family);
break;
case uiAttributeTypeFeatures:
uiFreeOpenTypeFeatures(a->u.features);
break;
}
uiprivFree(a);
}
void uiprivAttributeRelease(uiAttribute *a)
{
if (a->ownedByUser)
/* TODO implementation bug: we can't release an attribute we don't own */;
a->refcount--;
if (a->refcount == 0)
destroy(a);
}
void uiFreeAttribute(uiAttribute *a)
{
if (!a->ownedByUser)
/* TODO user bug: you can't free an attribute you don't own */;
destroy(a);
}
uiAttributeType uiAttributeGetType(const uiAttribute *a)
{
return a->type;
}
uiAttribute *uiNewFamilyAttribute(const char *family)
{
uiAttribute *a;
a = newAttribute(uiAttributeTypeFamily);
a->u.family = (char *) uiprivAlloc((strlen(family) + 1) * sizeof (char), "char[] (uiAttribute)");
strcpy(a->u.family, family);
return a;
}
const char *uiAttributeFamily(const uiAttribute *a)
{
return a->u.family;
}
uiAttribute *uiNewSizeAttribute(double size)
{
uiAttribute *a;
a = newAttribute(uiAttributeTypeSize);
a->u.size = size;
return a;
}
double uiAttributeSize(const uiAttribute *a)
{
return a->u.size;
}
uiAttribute *uiNewWeightAttribute(uiTextWeight weight)
{
uiAttribute *a;
a = newAttribute(uiAttributeTypeWeight);
a->u.weight = weight;
return a;
}
uiTextWeight uiAttributeWeight(const uiAttribute *a)
{
return a->u.weight;
}
uiAttribute *uiNewItalicAttribute(uiTextItalic italic)
{
uiAttribute *a;
a = newAttribute(uiAttributeTypeItalic);
a->u.italic = italic;
return a;
}
uiTextItalic uiAttributeItalic(const uiAttribute *a)
{
return a->u.italic;
}
uiAttribute *uiNewStretchAttribute(uiTextStretch stretch)
{
uiAttribute *a;
a = newAttribute(uiAttributeTypeStretch);
a->u.stretch = stretch;
return a;
}
uiTextStretch uiAttributeStretch(const uiAttribute *a)
{
return a->u.stretch;
}
uiAttribute *uiNewColorAttribute(double r, double g, double b, double a)
{
uiAttribute *at;
at = newAttribute(uiAttributeTypeColor);
at->u.color.r = r;
at->u.color.g = g;
at->u.color.b = b;
at->u.color.a = a;
return at;
}
void uiAttributeColor(const uiAttribute *a, double *r, double *g, double *b, double *alpha)
{
*r = a->u.color.r;
*g = a->u.color.g;
*b = a->u.color.b;
*alpha = a->u.color.a;
}
uiAttribute *uiNewBackgroundAttribute(double r, double g, double b, double a)
{
uiAttribute *at;
at = newAttribute(uiAttributeTypeBackground);
at->u.color.r = r;
at->u.color.g = g;
at->u.color.b = b;
at->u.color.a = a;
return at;
}
uiAttribute *uiNewUnderlineAttribute(uiUnderline u)
{
uiAttribute *a;
a = newAttribute(uiAttributeTypeUnderline);
a->u.underline = u;
return a;
}
uiUnderline uiAttributeUnderline(const uiAttribute *a)
{
return a->u.underline;
}
uiAttribute *uiNewUnderlineColorAttribute(uiUnderlineColor u, double r, double g, double b, double a)
{
uiAttribute *at;
at = uiNewColorAttribute(r, g, b, a);
at->type = uiAttributeTypeUnderlineColor;
at->u.color.underlineColor = u;
return at;
}
void uiAttributeUnderlineColor(const uiAttribute *a, uiUnderlineColor *u, double *r, double *g, double *b, double *alpha)
{
*u = a->u.color.underlineColor;
uiAttributeColor(a, r, g, b, alpha);
}
uiAttribute *uiNewFeaturesAttribute(const uiOpenTypeFeatures *otf)
{
uiAttribute *a;
a = newAttribute(uiAttributeTypeFeatures);
a->u.features = uiOpenTypeFeaturesClone(otf);
return a;
}
const uiOpenTypeFeatures *uiAttributeFeatures(const uiAttribute *a)
{
return a->u.features;
}
int uiprivAttributeEqual(const uiAttribute *a, const uiAttribute *b)
{
if (a == b)
return 1;
if (a->type != b->type)
return 0;
switch (a->type) {
case uiAttributeTypeFamily:
return uiprivStricmp(a->u.family, b->u.family);
case uiAttributeTypeSize:
// TODO is the use of == correct?
return a->u.size == b->u.size;
case uiAttributeTypeWeight:
return a->u.weight == b->u.weight;
case uiAttributeTypeItalic:
return a->u.italic == b->u.italic;
case uiAttributeTypeStretch:
return a->u.stretch == b->u.stretch;
case uiAttributeTypeUnderline:
return a->u.underline == b->u.underline;
case uiAttributeTypeUnderlineColor:
if (a->u.color.underlineColor != b->u.color.underlineColor)
return 0;
// fall through
case uiAttributeTypeColor:
case uiAttributeTypeBackground:
// TODO is the use of == correct?
return (a->u.color.r == b->u.color.r) &&
(a->u.color.g == b->u.color.g) &&
(a->u.color.b == b->u.color.b) &&
(a->u.color.a == b->u.color.a);
case uiAttributeTypeFeatures:
return uiprivOpenTypeFeaturesEqual(a->u.features, b->u.features);
}
// TODO should not be reached
return 0;
}
+612
View File
@@ -0,0 +1,612 @@
// 16 december 2016
#include "../ui.h"
#include "uipriv.h"
#include "attrstr.h"
/*
An attribute list is a doubly linked list of attributes.
Attribute start positions are inclusive and attribute end positions are exclusive (or in other words, [start, end)).
The list is kept sorted in increasing order by start position. Whether or not the sort is stable is undefined, so no temporal information should be expected to stay.
Overlapping attributes are not allowed; if an attribute is added that conflicts with an existing one, the existing one is removed.
In addition, the linked list tries to reduce fragmentation: if an attribute is added that just expands another, then there will only be one entry in alist, not two. (TODO does it really?)
The linked list is not a ring; alist->fist->prev == NULL and alist->last->next == NULL.
TODO verify that this disallows attributes of length zero
*/
struct attr {
uiAttribute *val;
size_t start;
size_t end;
struct attr *prev;
struct attr *next;
};
struct uiprivAttrList {
struct attr *first;
struct attr *last;
};
// if before is NULL, add to the end of the list
static void attrInsertBefore(uiprivAttrList *alist, struct attr *a, struct attr *before)
{
// if the list is empty, this is the first item
if (alist->first == NULL) {
alist->first = a;
alist->last = a;
return;
}
// add to the end
if (before == NULL) {
struct attr *oldlast;
oldlast = alist->last;
alist->last = a;
a->prev = oldlast;
oldlast->next = a;
return;
}
// add to the beginning
if (before == alist->first) {
struct attr *oldfirst;
oldfirst = alist->first;
alist->first = a;
oldfirst->prev = a;
a->next = oldfirst;
return;
}
// add to the middle
a->prev = before->prev;
a->next = before;
before->prev = a;
a->prev->next = a;
}
static int attrHasPos(struct attr *a, size_t pos)
{
if (pos < a->start)
return 0;
return pos < a->end;
}
// returns 1 if there was an intersection and 0 otherwise
static int attrRangeIntersect(struct attr *a, size_t *start, size_t *end)
{
// is the range outside a entirely?
if (*start >= a->end)
return 0;
if (*end < a->start)
return 0;
// okay, so there is an overlap
// compute the intersection
if (*start < a->start)
*start = a->start;
if (*end > a->end)
*end = a->end;
return 1;
}
// returns the old a->next, for forward iteration
static struct attr *attrUnlink(uiprivAttrList *alist, struct attr *a)
{
struct attr *p, *n;
p = a->prev;
n = a->next;
a->prev = NULL;
a->next = NULL;
// only item in list?
if (p == NULL && n == NULL) {
alist->first = NULL;
alist->last = NULL;
return NULL;
}
// start of list?
if (p == NULL) {
n->prev = NULL;
alist->first = n;
return n;
}
// end of list?
if (n == NULL) {
p->next = NULL;
alist->last = p;
return NULL;
}
// middle of list
p->next = n;
n->prev = p;
return n;
}
// returns the old a->next, for forward iteration
static struct attr *attrDelete(uiprivAttrList *alist, struct attr *a)
{
struct attr *next;
next = attrUnlink(alist, a);
uiprivAttributeRelease(a->val);
uiprivFree(a);
return next;
}
// attrDropRange() removes attributes without deleting characters.
//
// If the attribute needs no change, then nothing is done.
//
// If the attribute needs to be deleted, it is deleted.
//
// If the attribute only needs to be resized at the end, it is adjusted.
//
// If the attribute only needs to be resized at the start, it is adjusted, unlinked, and returned in tail.
//
// Otherwise, the attribute needs to be split. The existing attribute is adjusted to make the left half and a new attribute with the right half. This attribute is kept unlinked and returned in tail.
//
// In all cases, the return value is the next attribute to look at in a forward sequential loop.
static struct attr *attrDropRange(uiprivAttrList *alist, struct attr *a, size_t start, size_t end, struct attr **tail)
{
struct attr *b;
// always pre-initialize tail to NULL
*tail = NULL;
if (!attrRangeIntersect(a, &start, &end))
// out of range; nothing to do
return a->next;
// just outright delete the attribute?
// the inequalities handle attributes entirely inside the range
// if both are equal, the attribute's range is equal to the range
if (a->start >= start && a->end <= end)
return attrDelete(alist, a);
// only chop off the start or end?
if (a->start == start) { // chop off the start
// we are dropping the left half, so set a->start and unlink
a->start = end;
*tail = a;
return attrUnlink(alist, a);
}
if (a->end == end) { // chop off the end
// we are dropping the right half, so just set a->end
a->end = start;
return a->next;
}
// we'll need to split the attribute into two
b = uiprivNew(struct attr);
b->val = uiprivAttributeRetain(a->val);
b->start = end;
b->end = a->end;
*tail = b;
a->end = start;
return a->next;
}
static void attrGrow(uiprivAttrList *alist, struct attr *a, size_t start, size_t end)
{
struct attr *before;
// adjusting the end is simple: if it ends before our new end, just set the new end
if (a->end < end)
a->end = end;
// adjusting the start is harder
// if the start is before our new start, we are done
// otherwise, we have to move the start back AND reposition the attribute to keep the sorted order
if (a->start <= start)
return;
a->start = start;
attrUnlink(alist, a);
for (before = alist->first; before != NULL; before = before->next)
if (before->start > a->start)
break;
attrInsertBefore(alist, a, before);
}
// returns the right side of the split, which is unlinked, or NULL if no split was done
static struct attr *attrSplitAt(uiprivAttrList *alist, struct attr *a, size_t at)
{
struct attr *b;
// no splittng needed?
// note the equality: we don't need to split at start or end
// in the end case, the last split point is at - 1; at itself is outside the range, and at - 1 results in the right hand side having length 1
if (at <= a->start)
return NULL;
if (at >= a->end)
return NULL;
b = uiprivNew(struct attr);
b->val = uiprivAttributeRetain(a->val);
b->start = at;
b->end = a->end;
a->end = at;
return b;
}
// attrDeleteRange() removes attributes while deleting characters.
//
// If the attribute does not include the deleted range, then nothing is done (though the start and end are adjusted as necessary).
//
// If the attribute needs to be deleted, it is deleted.
//
// Otherwise, the attribute only needs the start or end deleted, and it is adjusted.
//
// In all cases, the return value is the next attribute to look at in a forward sequential loop.
// TODO rewrite this comment
static struct attr *attrDeleteRange(uiprivAttrList *alist, struct attr *a, size_t start, size_t end)
{
size_t ostart, oend;
size_t count;
ostart = start;
oend = end;
count = oend - ostart;
if (!attrRangeIntersect(a, &start, &end)) {
// out of range
// adjust if necessary
if (a->start >= ostart)
a->start -= count;
if (a->end >= oend)
a->end -= count;
return a->next;
}
// just outright delete the attribute?
// the inequalities handle attributes entirely inside the range
// if both are equal, the attribute's range is equal to the range
if (a->start >= start && a->end <= end)
return attrDelete(alist, a);
// only chop off the start or end?
if (a->start == start) { // chop off the start
// if we weren't adjusting positions this would just be setting a->start to end
// but since this is deleting from the start, we need to adjust both by count
a->start = end - count;
a->end -= count;
return a->next;
}
if (a->end == end) { // chop off the end
// a->start is already good
a->end = start;
return a->next;
}
// in this case, the deleted range is inside the attribute
// we can clear it by just removing count from a->end
a->end -= count;
return a->next;
}
uiprivAttrList *uiprivNewAttrList(void)
{
return uiprivNew(uiprivAttrList);
}
void uiprivFreeAttrList(uiprivAttrList *alist)
{
struct attr *a, *next;
a = alist->first;
while (a != NULL) {
next = a->next;
uiprivAttributeRelease(a->val);
uiprivFree(a);
a = next;
}
uiprivFree(alist);
}
void uiprivAttrListInsertAttribute(uiprivAttrList *alist, uiAttribute *val, size_t start, size_t end)
{
struct attr *a;
struct attr *before;
struct attr *tail = NULL;
int split = 0;
uiAttributeType valtype;
// first, figure out where in the list this should go
// in addition, if this attribute overrides one that already exists, split that one apart so this one can take over
before = alist->first;
valtype = uiAttributeGetType(val);
while (before != NULL) {
size_t lstart, lend;
// once we get to the first point after start, we know where to insert
if (before->start > start)
break;
// if we have already split a prior instance of this attribute, don't bother doing it again
if (split)
goto next;
// should we split this attribute?
if (uiAttributeGetType(before->val) != valtype)
goto next;
lstart = start;
lend = end;
if (!attrRangeIntersect(before, &lstart, &lend))
goto next;
// okay so this might conflict; if the val is the same as the one we want, we need to expand the existing attribute, not fragment anything
// TODO will this reduce fragmentation if we first add from 0 to 2 and then from 2 to 4? or do we have to do that separately?
if (uiprivAttributeEqual(before->val, val)) {
attrGrow(alist, before, start, end);
return;
}
// okay the values are different; we need to split apart
before = attrDropRange(alist, before, start, end, &tail);
split = 1;
continue;
next:
before = before->next;
}
// if we got here, we know we have to add the attribute before before
a = uiprivNew(struct attr);
a->val = uiprivAttributeRetain(val);
a->start = start;
a->end = end;
attrInsertBefore(alist, a, before);
// and finally, if we split, insert the remainder
if (tail == NULL)
return;
// note we start at before; it won't be inserted before that by the sheer nature of how the code above works
for (; before != NULL; before = before->next)
if (before->start > tail->start)
break;
attrInsertBefore(alist, tail, before);
}
void uiprivAttrListInsertCharactersUnattributed(uiprivAttrList *alist, size_t start, size_t count)
{
struct attr *a;
struct attr *tails = NULL;
// every attribute before the insertion point can either cross into the insertion point or not
// if it does, we need to split that attribute apart at the insertion point, keeping only the old attribute in place, adjusting the new tail, and preparing it for being re-added later
for (a = alist->first; a != NULL; a = a->next) {
struct attr *tail;
// stop once we get to the insertion point
if (a->start >= start)
break;
// only do something if overlapping
if (!attrHasPos(a, start))
continue;
tail = attrSplitAt(alist, a, start);
// adjust the new tail for the insertion
tail->start += count;
tail->end += count;
// and queue it for re-adding later
// we can safely use tails as if it was singly-linked since it's just a temporary list; we properly merge them back in below and they'll be doubly-linked again then
// TODO actually we could probably save some time by making then doubly-linked now and adding them in one fell swoop, but that would make things a bit more complicated...
tail->next = tails;
tails = tail;
}
// at this point in the attribute list, we are at or after the insertion point
// all the split-apart attributes will be at the insertion point
// therefore, we can just add them all back now, and the list will still be sorted correctly
while (tails != NULL) {
struct attr *next;
// make all the links NULL before insertion, just to be safe
next = tails->next;
tails->next = NULL;
attrInsertBefore(alist, tails, a);
tails = next;
}
// every remaining attribute will be either at or after the insertion point
// we just need to move them ahead
for (; a != NULL; a = a->next) {
a->start += count;
a->end += count;
}
}
// The attributes are those of character start - 1.
// If start == 0, the attributes are those of character 0.
/*
This is an obtuse function. Here's some diagrams to help.
Given the input string
abcdefghi (positions: 012345678 9)
and attribute set
red start 0 end 3
bold start 2 end 6
underline start 5 end 8
or visually:
012345678 9
rrr------
--bbbb---
-----uuu-
If we insert qwe to result in positions 0123456789AB C:
before 0, 1, 2 (grow the red part, move everything else down)
red -> start 0 (no change) end 3+3=6
bold -> start 2+3=5 end 6+3=9
underline -> start 5+3=8 end 8+3=B
before 3 (grow red and bold, move underline down)
red -> start 0 (no change) end 3+3=6
bold -> start 2 (no change) end 6+3=9
underline -> start 5+3=8 end 8+3=B
before 4, 5 (keep red, grow bold, move underline down)
red -> start 0 (no change) end 3 (no change)
bold -> start 2 (no change) end 6+3=9
underline -> start 5+3=8 end 8+3=B
before 6 (keep red, grow bold and underline)
red -> start 0 (no change) end 3 (no change)
bold -> start 2 (no change) end 6+3=9
underline -> start 5 (no change) end 8+3=B
before 7, 8 (keep red and bold, grow underline)
red -> start 0 (no change) end 3 (no change)
bold -> start 2 (no change) end 6 (no change)
underline -> start 5 (no change) end 8+3=B
before 9 (keep all three)
red -> start 0 (no change) end 3 (no change)
bold -> start 2 (no change) end 6 (no change)
underline -> start 5 (no change) end 8 (no change)
result:
0 1 2 3 4 5 6 7 8 9
red E E E e n n n n n n
bold s s S E E E e n n n
underline s s s s s S E E e n
N = none
E = end only
S = start and end
uppercase = in original range, lowercase = not
which results in our algorithm:
for each attribute
if start < insertion point
move start up
else if start == insertion point
if start != 0
move start up
if end <= insertion point
move end up
*/
// TODO does this ensure the list remains sorted?
void uiprivAttrListInsertCharactersExtendingAttributes(uiprivAttrList *alist, size_t start, size_t count)
{
struct attr *a;
for (a = alist->first; a != NULL; a = a->next) {
if (a->start < start)
a->start += count;
else if (a->start == start && start != 0)
a->start += count;
if (a->end <= start)
a->end += count;
}
}
// TODO replace at point with — replaces with first character's attributes
void uiprivAttrListRemoveAttribute(uiprivAttrList *alist, uiAttributeType type, size_t start, size_t end)
{
struct attr *a;
struct attr *tails = NULL; // see uiprivAttrListInsertCharactersUnattributed() above
struct attr *tailsAt = NULL;
a = alist->first;
while (a != NULL) {
size_t lstart, lend;
struct attr *tail;
// this defines where to re-attach the tails
// (all the tails will have their start at end, so we can just insert them all before tailsAt)
if (a->start >= end) {
tailsAt = a;
// and at this point we're done, so
break;
}
if (uiAttributeGetType(a->val) != type)
goto next;
lstart = start;
lend = end;
if (!attrRangeIntersect(a, &lstart, &lend))
goto next;
a = attrDropRange(alist, a, start, end, &tail);
if (tail != NULL) {
tail->next = tails;
tails = tail;
}
continue;
next:
a = a->next;
}
while (tails != NULL) {
struct attr *next;
// make all the links NULL before insertion, just to be safe
next = tails->next;
tails->next = NULL;
attrInsertBefore(alist, tails, a);
tails = next;
}
}
// TODO merge this with the above
void uiprivAttrListRemoveAttributes(uiprivAttrList *alist, size_t start, size_t end)
{
struct attr *a;
struct attr *tails = NULL; // see uiprivAttrListInsertCharactersUnattributed() above
struct attr *tailsAt = NULL;
a = alist->first;
while (a != NULL) {
size_t lstart, lend;
struct attr *tail;
// this defines where to re-attach the tails
// (all the tails will have their start at end, so we can just insert them all before tailsAt)
if (a->start >= end) {
tailsAt = a;
// and at this point we're done, so
break;
}
lstart = start;
lend = end;
if (!attrRangeIntersect(a, &lstart, &lend))
goto next;
a = attrDropRange(alist, a, start, end, &tail);
if (tail != NULL) {
tail->next = tails;
tails = tail;
}
continue;
next:
a = a->next;
}
while (tails != NULL) {
struct attr *next;
// make all the links NULL before insertion, just to be safe
next = tails->next;
tails->next = NULL;
attrInsertBefore(alist, tails, a);
tails = next;
}
}
void uiprivAttrListRemoveCharacters(uiprivAttrList *alist, size_t start, size_t end)
{
struct attr *a;
a = alist->first;
while (a != NULL)
a = attrDeleteRange(alist, a, start, end);
}
void uiprivAttrListForEach(const uiprivAttrList *alist, const uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data)
{
struct attr *a;
uiForEach ret;
for (a = alist->first; a != NULL; a = a->next) {
ret = (*f)(s, a->val, a->start, a->end, data);
if (ret == uiForEachStop)
// TODO for all: break or return?
break;
}
}
+357
View File
@@ -0,0 +1,357 @@
// 3 december 2016
#include "../ui.h"
#include "uipriv.h"
#include "attrstr.h"
struct uiAttributedString {
char *s;
size_t len;
uiprivAttrList *attrs;
// indiscriminately keep a UTF-16 copy of the string on all platforms so we can hand this off to the grapheme calculator
// this ensures no one platform has a speed advantage (sorry GTK+)
uint16_t *u16;
size_t u16len;
size_t *u8tou16;
size_t *u16tou8;
// this is lazily created to keep things from getting *too* slow
uiprivGraphemes *graphemes;
};
static void resize(uiAttributedString *s, size_t u8, size_t u16)
{
s->len = u8;
s->s = (char *) uiprivRealloc(s->s, (s->len + 1) * sizeof (char), "char[] (uiAttributedString)");
s->u8tou16 = (size_t *) uiprivRealloc(s->u8tou16, (s->len + 1) * sizeof (size_t), "size_t[] (uiAttributedString)");
s->u16len = u16;
s->u16 = (uint16_t *) uiprivRealloc(s->u16, (s->u16len + 1) * sizeof (uint16_t), "uint16_t[] (uiAttributedString)");
s->u16tou8 = (size_t *) uiprivRealloc(s->u16tou8, (s->u16len + 1) * sizeof (size_t), "size_t[] (uiAttributedString)");
}
uiAttributedString *uiNewAttributedString(const char *initialString)
{
uiAttributedString *s;
s = uiprivNew(uiAttributedString);
s->attrs = uiprivNewAttrList();
uiAttributedStringAppendUnattributed(s, initialString);
return s;
}
// TODO make sure that all implementations of uiprivNewGraphemes() work fine with empty strings; in particular, the Windows one might not
static void recomputeGraphemes(uiAttributedString *s)
{
if (s->graphemes != NULL)
return;
if (uiprivGraphemesTakesUTF16()) {
s->graphemes = uiprivNewGraphemes(s->u16, s->u16len);
return;
}
s->graphemes = uiprivNewGraphemes(s->s, s->len);
}
static void invalidateGraphemes(uiAttributedString *s)
{
if (s->graphemes == NULL)
return;
uiprivFree(s->graphemes->pointsToGraphemes);
uiprivFree(s->graphemes->graphemesToPoints);
uiprivFree(s->graphemes);
s->graphemes = NULL;
}
void uiFreeAttributedString(uiAttributedString *s)
{
uiprivFreeAttrList(s->attrs);
invalidateGraphemes(s);
uiprivFree(s->u16tou8);
uiprivFree(s->u8tou16);
uiprivFree(s->u16);
uiprivFree(s->s);
uiprivFree(s);
}
const char *uiAttributedStringString(const uiAttributedString *s)
{
return s->s;
}
size_t uiAttributedStringLen(const uiAttributedString *s)
{
return s->len;
}
static void u8u16len(const char *str, size_t *n8, size_t *n16)
{
uint32_t rune;
char buf[4];
uint16_t buf16[2];
*n8 = 0;
*n16 = 0;
while (*str) {
str = uiprivUTF8DecodeRune(str, 0, &rune);
// TODO document the use of the function vs a pointer subtract here
// TODO also we need to consider namespace collision with utf.h...
*n8 += uiprivUTF8EncodeRune(rune, buf);
*n16 += uiprivUTF16EncodeRune(rune, buf16);
}
}
void uiAttributedStringAppendUnattributed(uiAttributedString *s, const char *str)
{
uiAttributedStringInsertAtUnattributed(s, str, s->len);
}
// this works (and returns true, which is what we want) at s->len too because s->s[s->len] is always going to be 0 due to us allocating s->len + 1 bytes and because uiprivRealloc() always zero-fills allocated memory
static int onCodepointBoundary(uiAttributedString *s, size_t at)
{
uint8_t c;
// for uiNewAttributedString()
if (s->s == NULL && at == 0)
return 1;
c = (uint8_t) (s->s[at]);
return c < 0x80 || c >= 0xC0;
}
// TODO note that at must be on a codeoint boundary
void uiAttributedStringInsertAtUnattributed(uiAttributedString *s, const char *str, size_t at)
{
uint32_t rune;
char buf[4];
uint16_t buf16[2];
size_t n8, n16; // TODO make loop-local? to avoid using them in the wrong place again
size_t old, old16;
size_t oldn8, oldn16;
size_t oldlen, old16len;
size_t at16;
size_t i;
if (!onCodepointBoundary(s, at)) {
// TODO
}
at16 = 0;
if (s->u8tou16 != NULL)
at16 = s->u8tou16[at];
// do this first to reclaim memory
invalidateGraphemes(s);
// first figure out how much we need to grow by
// this includes post-validated UTF-8
u8u16len(str, &n8, &n16);
// and resize
old = at;
old16 = at16;
oldlen = s->len;
old16len = s->u16len;
resize(s, s->len + n8, s->u16len + n16);
// move existing characters out of the way
// note the use of memmove(): https://twitter.com/rob_pike/status/737797688217894912
memmove(
s->s + at + n8,
s->s + at,
(oldlen - at) * sizeof (char));
memmove(
s->u16 + at16 + n16,
s->u16 + at16,
(old16len - at16) * sizeof (uint16_t));
// note the + 1 for these; we want to copy the terminating null too
memmove(
s->u8tou16 + at + n8,
s->u8tou16 + at,
(oldlen - at + 1) * sizeof (size_t));
memmove(
s->u16tou8 + at16 + n16,
s->u16tou8 + at16,
(old16len - at16 + 1) * sizeof (size_t));
oldn8 = n8;
oldn16 = n16;
// and copy
while (*str) {
size_t n;
str = uiprivUTF8DecodeRune(str, 0, &rune);
n = uiprivUTF8EncodeRune(rune, buf);
n16 = uiprivUTF16EncodeRune(rune, buf16);
s->s[old] = buf[0];
s->u8tou16[old] = old16;
if (n > 1) {
s->s[old + 1] = buf[1];
s->u8tou16[old + 1] = old16;
}
if (n > 2) {
s->s[old + 2] = buf[2];
s->u8tou16[old + 2] = old16;
}
if (n > 3) {
s->s[old + 3] = buf[3];
s->u8tou16[old + 3] = old16;
}
s->u16[old16] = buf16[0];
s->u16tou8[old16] = old;
if (n16 > 1) {
s->u16[old16 + 1] = buf16[1];
s->u16tou8[old16 + 1] = old;
}
old += n;
old16 += n16;
}
// and have an index for the end of the string
// TODO is this done by the below?
//TODO s->u8tou16[old] = old16;
//TODO s->u16tou8[old16] = old;
// and adjust the prior values in the conversion tables
// use <= so the terminating 0 gets updated too
for (i = 0; i <= oldlen - at; i++)
s->u8tou16[at + oldn8 + i] += s->u16len - old16len;
for (i = 0; i <= old16len - at16; i++)
s->u16tou8[at16 + oldn16 + i] += s->len - oldlen;
// and finally do the attributes
uiprivAttrListInsertCharactersUnattributed(s->attrs, at, n8);
}
// TODO document that end is the first index that will be maintained
void uiAttributedStringDelete(uiAttributedString *s, size_t start, size_t end)
{
size_t start16, end16;
size_t count, count16;
size_t i;
if (!onCodepointBoundary(s, start)) {
// TODO
}
if (!onCodepointBoundary(s, end)) {
// TODO
}
count = end - start;
start16 = s->u8tou16[start];
end16 = s->u8tou16[end];
count16 = end16 - start16;
invalidateGraphemes(s);
// overwrite old characters
memmove(
s->s + start,
s->s + end,
(s->len - end) * sizeof (char));
memmove(
s->u16 + start16,
s->u16 + end16,
(s->u16len - end16) * sizeof (uint16_t));
// note the + 1 for these; we want to copy the terminating null too
memmove(
s->u8tou16 + start,
s->u8tou16 + end,
(s->len - end + 1) * sizeof (size_t));
memmove(
s->u16tou8 + start16,
s->u16tou8 + end16,
(s->u16len - end16 + 1) * sizeof (size_t));
// update the conversion tables
// note the use of <= to include the null terminator
for (i = 0; i <= (s->len - end); i++)
s->u8tou16[start + i] -= count16;
for (i = 0; i <= (s->u16len - end16); i++)
s->u16tou8[start16 + i] -= count;
// null-terminate the string
s->s[start + (s->len - end)] = 0;
s->u16[start16 + (s->u16len - end16)] = 0;
// fix up attributes
uiprivAttrListRemoveCharacters(s->attrs, start, end);
// and finally resize
resize(s, s->len - count, s->u16len - count16);
}
void uiAttributedStringSetAttribute(uiAttributedString *s, uiAttribute *a, size_t start, size_t end)
{
uiprivAttrListInsertAttribute(s->attrs, a, start, end);
}
// LONGTERM introduce an iterator object instead?
void uiAttributedStringForEachAttribute(const uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data)
{
uiprivAttrListForEach(s->attrs, s, f, data);
}
// TODO figure out if we should count the grapheme past the end
size_t uiAttributedStringNumGraphemes(uiAttributedString *s)
{
recomputeGraphemes(s);
return s->graphemes->len;
}
size_t uiAttributedStringByteIndexToGrapheme(uiAttributedString *s, size_t pos)
{
recomputeGraphemes(s);
if (uiprivGraphemesTakesUTF16())
pos = s->u8tou16[pos];
return s->graphemes->pointsToGraphemes[pos];
}
size_t uiAttributedStringGraphemeToByteIndex(uiAttributedString *s, size_t pos)
{
recomputeGraphemes(s);
pos = s->graphemes->graphemesToPoints[pos];
if (uiprivGraphemesTakesUTF16())
pos = s->u16tou8[pos];
return pos;
}
// helpers for platform-specific code
const uint16_t *uiprivAttributedStringUTF16String(const uiAttributedString *s)
{
return s->u16;
}
size_t uiprivAttributedStringUTF16Len(const uiAttributedString *s)
{
return s->u16len;
}
// TODO is this still needed given the below?
size_t uiprivAttributedStringUTF8ToUTF16(const uiAttributedString *s, size_t n)
{
return s->u8tou16[n];
}
size_t *uiprivAttributedStringCopyUTF8ToUTF16Table(const uiAttributedString *s, size_t *n)
{
size_t *out;
size_t nbytes;
nbytes = (s->len + 1) * sizeof (size_t);
*n = s->len;
out = (size_t *) uiprivAlloc(nbytes, "size_t[] (uiAttributedString)");
memmove(out, s->u8tou16, nbytes);
return out;
}
size_t *uiprivAttributedStringCopyUTF16ToUTF8Table(const uiAttributedString *s, size_t *n)
{
size_t *out;
size_t nbytes;
nbytes = (s->u16len + 1) * sizeof (size_t);
*n = s->u16len;
out = (size_t *) uiprivAlloc(nbytes, "size_t[] (uiAttributedString)");
memmove(out, s->u16tou8, nbytes);
return out;
}
+46
View File
@@ -0,0 +1,46 @@
// 19 february 2018
#ifdef __cplusplus
extern "C" {
#endif
// attribute.c
extern uiAttribute *uiprivAttributeRetain(uiAttribute *a);
extern void uiprivAttributeRelease(uiAttribute *a);
extern int uiprivAttributeEqual(const uiAttribute *a, const uiAttribute *b);
// opentype.c
extern int uiprivOpenTypeFeaturesEqual(const uiOpenTypeFeatures *a, const uiOpenTypeFeatures *b);
// attrlist.c
typedef struct uiprivAttrList uiprivAttrList;
extern uiprivAttrList *uiprivNewAttrList(void);
extern void uiprivFreeAttrList(uiprivAttrList *alist);
extern void uiprivAttrListInsertAttribute(uiprivAttrList *alist, uiAttribute *val, size_t start, size_t end);
extern void uiprivAttrListInsertCharactersUnattributed(uiprivAttrList *alist, size_t start, size_t count);
extern void uiprivAttrListInsertCharactersExtendingAttributes(uiprivAttrList *alist, size_t start, size_t count);
extern void uiprivAttrListRemoveAttribute(uiprivAttrList *alist, uiAttributeType type, size_t start, size_t end);
extern void uiprivAttrListRemoveAttributes(uiprivAttrList *alist, size_t start, size_t end);
extern void uiprivAttrListRemoveCharacters(uiprivAttrList *alist, size_t start, size_t end);
extern void uiprivAttrListForEach(const uiprivAttrList *alist, const uiAttributedString *s, uiAttributedStringForEachAttributeFunc f, void *data);
// attrstr.c
extern const uint16_t *uiprivAttributedStringUTF16String(const uiAttributedString *s);
extern size_t uiprivAttributedStringUTF16Len(const uiAttributedString *s);
extern size_t uiprivAttributedStringUTF8ToUTF16(const uiAttributedString *s, size_t n);
extern size_t *uiprivAttributedStringCopyUTF8ToUTF16Table(const uiAttributedString *s, size_t *n);
extern size_t *uiprivAttributedStringCopyUTF16ToUTF8Table(const uiAttributedString *s, size_t *n);
// per-OS graphemes.c/graphemes.cpp/graphemes.m/etc.
typedef struct uiprivGraphemes uiprivGraphemes;
struct uiprivGraphemes {
size_t len;
size_t *pointsToGraphemes;
size_t *graphemesToPoints;
};
extern int uiprivGraphemesTakesUTF16(void);
extern uiprivGraphemes *uiprivNewGraphemes(void *s, size_t len);
#ifdef __cplusplus
}
#endif
+101
View File
@@ -0,0 +1,101 @@
// 26 may 2015
#include "../ui.h"
#include "uipriv.h"
void uiControlDestroy(uiControl *c)
{
(*(c->Destroy))(c);
}
uintptr_t uiControlHandle(uiControl *c)
{
return (*(c->Handle))(c);
}
uiControl *uiControlParent(uiControl *c)
{
return (*(c->Parent))(c);
}
void uiControlSetParent(uiControl *c, uiControl *parent)
{
(*(c->SetParent))(c, parent);
}
int uiControlToplevel(uiControl *c)
{
return (*(c->Toplevel))(c);
}
int uiControlVisible(uiControl *c)
{
return (*(c->Visible))(c);
}
void uiControlShow(uiControl *c)
{
(*(c->Show))(c);
}
void uiControlHide(uiControl *c)
{
(*(c->Hide))(c);
}
int uiControlEnabled(uiControl *c)
{
return (*(c->Enabled))(c);
}
void uiControlEnable(uiControl *c)
{
(*(c->Enable))(c);
}
void uiControlDisable(uiControl *c)
{
(*(c->Disable))(c);
}
#define uiprivControlSignature 0x7569436F
uiControl *uiAllocControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr)
{
uiControl *c;
c = (uiControl *) uiprivAlloc(size, typenamestr);
c->Signature = uiprivControlSignature;
c->OSSignature = OSsig;
c->TypeSignature = typesig;
return c;
}
void uiFreeControl(uiControl *c)
{
if (uiControlParent(c) != NULL)
uiprivUserBug("You cannot destroy a uiControl while it still has a parent. (control: %p)", c);
uiprivFree(c);
}
void uiControlVerifySetParent(uiControl *c, uiControl *parent)
{
uiControl *curParent;
if (uiControlToplevel(c))
uiprivUserBug("You cannot give a toplevel uiControl a parent. (control: %p)", c);
curParent = uiControlParent(c);
if (parent != NULL && curParent != NULL)
uiprivUserBug("You cannot give a uiControl a parent while it already has one. (control: %p; current parent: %p; new parent: %p)", c, curParent, parent);
if (parent == NULL && curParent == NULL)
uiprivImplBug("attempt to double unparent uiControl %p", c);
}
int uiControlEnabledToUser(uiControl *c)
{
while (c != NULL) {
if (!uiControlEnabled(c))
return 0;
c = uiControlParent(c);
}
return 1;
}
+27
View File
@@ -0,0 +1,27 @@
// 24 april 2016
// LONGTERM if I don't decide to remove these outright, should they be renamed uiprivTypeNameSignature? these aren't real symbols, so...
#define uiAreaSignature 0x41726561
#define uiBoxSignature 0x426F784C
#define uiButtonSignature 0x42746F6E
#define uiCheckboxSignature 0x43686B62
#define uiColorButtonSignature 0x436F6C42
#define uiComboboxSignature 0x436F6D62
#define uiDateTimePickerSignature 0x44545069
#define uiEditableComboboxSignature 0x45644362
#define uiEntrySignature 0x456E7472
#define uiFontButtonSignature 0x466F6E42
#define uiFormSignature 0x466F726D
#define uiGridSignature 0x47726964
#define uiGroupSignature 0x47727062
#define uiLabelSignature 0x4C61626C
#define uiMultilineEntrySignature 0x4D6C6E45
#define uiProgressBarSignature 0x50426172
#define uiRadioButtonsSignature 0x5264696F
#define uiSeparatorSignature 0x53657061
#define uiSliderSignature 0x536C6964
#define uiSpinboxSignature 0x5370696E
#define uiTabSignature 0x54616273
#define uiTableSignature 0x5461626C
#define uiWindowSignature 0x57696E64
+21
View File
@@ -0,0 +1,21 @@
// 13 may 2016
#include "../ui.h"
#include "uipriv.h"
void uiprivDoImplBug(const char *file, const char *line, const char *func, const char *format, ...)
{
va_list ap;
va_start(ap, format);
uiprivRealBug(file, line, func, "POSSIBLE IMPLEMENTATION BUG; CONTACT ANDLABS:\n", format, ap);
va_end(ap);
}
void uiprivDoUserBug(const char *file, const char *line, const char *func, const char *format, ...)
{
va_list ap;
va_start(ap, format);
uiprivRealBug(file, line, func, "You have a bug: ", format, ap);
va_end(ap);
}
+50
View File
@@ -0,0 +1,50 @@
// 11 october 2015
#include <math.h>
#include "../ui.h"
#include "uipriv.h"
void uiDrawMatrixSetIdentity(uiDrawMatrix *m)
{
m->M11 = 1;
m->M12 = 0;
m->M21 = 0;
m->M22 = 1;
m->M31 = 0;
m->M32 = 0;
}
// The rest of this file provides basic utilities in case the platform doesn't provide any of its own for these tasks.
// Keep these as minimal as possible. They should generally not call other fallbacks.
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ff684171%28v=vs.85%29.aspx#skew_transform
// TODO see if there's a way we can avoid the multiplication
void uiprivFallbackSkew(uiDrawMatrix *m, double x, double y, double xamount, double yamount)
{
uiDrawMatrix n;
uiDrawMatrixSetIdentity(&n);
// TODO explain this
n.M12 = tan(yamount);
n.M21 = tan(xamount);
n.M31 = -y * tan(xamount);
n.M32 = -x * tan(yamount);
uiDrawMatrixMultiply(m, &n);
}
void uiprivScaleCenter(double xCenter, double yCenter, double *x, double *y)
{
*x = xCenter - (*x * xCenter);
*y = yCenter - (*y * yCenter);
}
// the basic algorithm is from cairo
// but it's the same algorithm as the transform point, just without M31 and M32 taken into account, so let's just do that instead
void uiprivFallbackTransformSize(uiDrawMatrix *m, double *x, double *y)
{
uiDrawMatrix m2;
m2 = *m;
m2.M31 = 0;
m2.M32 = 0;
uiDrawMatrixTransformPoint(&m2, x, y);
}
+17
View File
@@ -0,0 +1,17 @@
# 23 march 2019
libui_sources += [
'common/attribute.c',
'common/attrlist.c',
'common/attrstr.c',
'common/areaevents.c',
'common/control.c',
'common/debug.c',
'common/matrix.c',
'common/opentype.c',
'common/shouldquit.c',
'common/tablemodel.c',
'common/tablevalue.c',
'common/userbugs.c',
'common/utf.c',
]
+165
View File
@@ -0,0 +1,165 @@
// 25 february 2018
#include <stdlib.h>
#include "../ui.h"
#include "uipriv.h"
#include "attrstr.h"
struct feature {
char a;
char b;
char c;
char d;
uint32_t value;
};
struct uiOpenTypeFeatures {
struct feature *data;
size_t len;
size_t cap;
};
#define bytecount(n) ((n) * sizeof (struct feature))
uiOpenTypeFeatures *uiNewOpenTypeFeatures(void)
{
uiOpenTypeFeatures *otf;
otf = uiprivNew(uiOpenTypeFeatures);
otf->cap = 16;
otf->data = (struct feature *) uiprivAlloc(bytecount(otf->cap), "struct feature[]");
otf->len = 0;
return otf;
}
void uiFreeOpenTypeFeatures(uiOpenTypeFeatures *otf)
{
uiprivFree(otf->data);
uiprivFree(otf);
}
uiOpenTypeFeatures *uiOpenTypeFeaturesClone(const uiOpenTypeFeatures *otf)
{
uiOpenTypeFeatures *ret;
ret = uiprivNew(uiOpenTypeFeatures);
ret->len = otf->len;
ret->cap = otf->cap;
ret->data = (struct feature *) uiprivAlloc(bytecount(ret->cap), "struct feature[]");
memset(ret->data, 0, bytecount(ret->cap));
memmove(ret->data, otf->data, bytecount(ret->len));
return ret;
}
#define intdiff(a, b) (((int) (a)) - ((int) (b)))
static int featurecmp(const void *a, const void *b)
{
const struct feature *f = (const struct feature *) a;
const struct feature *g = (const struct feature *) b;
if (f->a != g->a)
return intdiff(f->a, g->a);
if (f->b != g->b)
return intdiff(f->b, g->b);
if (f->c != g->c)
return intdiff(f->c, g->c);
return intdiff(f->d, g->d);
}
static struct feature mkkey(char a, char b, char c, char d)
{
struct feature f;
f.a = a;
f.b = b;
f.c = c;
f.d = d;
return f;
}
#define find(pkey, otf) bsearch(pkey, otf->data, otf->len, sizeof (struct feature), featurecmp)
void uiOpenTypeFeaturesAdd(uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t value)
{
struct feature *f;
struct feature key;
// replace existing value if any
key = mkkey(a, b, c, d);
f = (struct feature *) find(&key, otf);
if (f != NULL) {
f->value = value;
return;
}
// if we got here, the tag is new
if (otf->len == otf->cap) {
otf->cap *= 2;
otf->data = (struct feature *) uiprivRealloc(otf->data, bytecount(otf->cap), "struct feature[]");
}
f = otf->data + otf->len;
f->a = a;
f->b = b;
f->c = c;
f->d = d;
f->value = value;
// LONGTERM qsort here is overkill
otf->len++;
qsort(otf->data, otf->len, sizeof (struct feature), featurecmp);
}
void uiOpenTypeFeaturesRemove(uiOpenTypeFeatures *otf, char a, char b, char c, char d)
{
struct feature *f;
struct feature key;
ptrdiff_t index;
size_t count;
key = mkkey(a, b, c, d);
f = (struct feature *) find(&key, otf);
if (f == NULL)
return;
index = f - otf->data;
count = otf->len - index - 1;
memmove(f + 1, f, bytecount(count));
otf->len--;
}
int uiOpenTypeFeaturesGet(const uiOpenTypeFeatures *otf, char a, char b, char c, char d, uint32_t *value)
{
const struct feature *f;
struct feature key;
key = mkkey(a, b, c, d);
f = (const struct feature *) find(&key, otf);
if (f == NULL)
return 0;
*value = f->value;
return 1;
}
void uiOpenTypeFeaturesForEach(const uiOpenTypeFeatures *otf, uiOpenTypeFeaturesForEachFunc f, void *data)
{
size_t n;
const struct feature *p;
uiForEach ret;
p = otf->data;
for (n = 0; n < otf->len; n++) {
ret = (*f)(otf, p->a, p->b, p->c, p->d, p->value, data);
// TODO for all: require exact match?
if (ret == uiForEachStop)
return;
p++;
}
}
int uiprivOpenTypeFeaturesEqual(const uiOpenTypeFeatures *a, const uiOpenTypeFeatures *b)
{
if (a == b)
return 1;
if (a->len != b->len)
return 0;
return memcmp(a->data, b->data, bytecount(a->len)) == 0;
}
+22
View File
@@ -0,0 +1,22 @@
// 9 may 2015
#include "../ui.h"
#include "uipriv.h"
static int defaultOnShouldQuit(void *data)
{
return 0;
}
static int (*onShouldQuit)(void *) = defaultOnShouldQuit;
static void *onShouldQuitData = NULL;
void uiOnShouldQuit(int (*f)(void *), void *data)
{
onShouldQuit = f;
onShouldQuitData = data;
}
int uiprivShouldQuit(void)
{
return (*onShouldQuit)(onShouldQuitData);
}
+20
View File
@@ -0,0 +1,20 @@
// 23 june 2018
#ifdef __cplusplus
extern "C" {
#endif
// tablemodel.c
extern uiTableModelHandler *uiprivTableModelHandler(uiTableModel *m);
extern int uiprivTableModelNumColumns(uiTableModel *m);
extern uiTableValueType uiprivTableModelColumnType(uiTableModel *m, int column);
extern int uiprivTableModelNumRows(uiTableModel *m);
extern uiTableValue *uiprivTableModelCellValue(uiTableModel *m, int row, int column);
extern void uiprivTableModelSetCellValue(uiTableModel *m, int row, int column, const uiTableValue *value);
extern const uiTableTextColumnOptionalParams uiprivDefaultTextColumnOptionalParams;
extern int uiprivTableModelCellEditable(uiTableModel *m, int row, int column);
extern int uiprivTableModelColorIfProvided(uiTableModel *m, int row, int column, double *r, double *g, double *b, double *a);
#ifdef __cplusplus
}
#endif
+81
View File
@@ -0,0 +1,81 @@
// 23 june 2018
#include "../ui.h"
#include "uipriv.h"
#include "table.h"
int uiprivTableModelNumColumns(uiTableModel *m)
{
uiTableModelHandler *mh;
mh = uiprivTableModelHandler(m);
return (*(mh->NumColumns))(mh, m);
}
uiTableValueType uiprivTableModelColumnType(uiTableModel *m, int column)
{
uiTableModelHandler *mh;
mh = uiprivTableModelHandler(m);
return (*(mh->ColumnType))(mh, m, column);
}
int uiprivTableModelNumRows(uiTableModel *m)
{
uiTableModelHandler *mh;
mh = uiprivTableModelHandler(m);
return (*(mh->NumRows))(mh, m);
}
uiTableValue *uiprivTableModelCellValue(uiTableModel *m, int row, int column)
{
uiTableModelHandler *mh;
mh = uiprivTableModelHandler(m);
return (*(mh->CellValue))(mh, m, row, column);
}
void uiprivTableModelSetCellValue(uiTableModel *m, int row, int column, const uiTableValue *value)
{
uiTableModelHandler *mh;
mh = uiprivTableModelHandler(m);
(*(mh->SetCellValue))(mh, m, row, column, value);
uiTableModelRowChanged(m, row);
}
const uiTableTextColumnOptionalParams uiprivDefaultTextColumnOptionalParams = {
.ColorModelColumn = -1,
};
int uiprivTableModelCellEditable(uiTableModel *m, int row, int column)
{
uiTableValue *value;
int editable;
switch (column) {
case uiTableModelColumnNeverEditable:
return 0;
case uiTableModelColumnAlwaysEditable:
return 1;
}
value = uiprivTableModelCellValue(m, row, column);
editable = uiTableValueInt(value);
uiFreeTableValue(value);
return editable;
}
int uiprivTableModelColorIfProvided(uiTableModel *m, int row, int column, double *r, double *g, double *b, double *a)
{
uiTableValue *value;
if (column == -1)
return 0;
value = uiprivTableModelCellValue(m, row, column);
if (value == NULL)
return 0;
uiTableValueColor(value, r, g, b, a);
uiFreeTableValue(value);
return 1;
}
+106
View File
@@ -0,0 +1,106 @@
// 3 june 2018
#include "../ui.h"
#include "uipriv.h"
#include "table.h"
struct uiTableValue {
uiTableValueType type;
union {
char *str;
uiImage *img;
int i;
struct {
double r;
double g;
double b;
double a;
} color;
} u;
};
static uiTableValue *newTableValue(uiTableValueType type)
{
uiTableValue *v;
v = uiprivNew(uiTableValue);
v->type = type;
return v;
}
void uiFreeTableValue(uiTableValue *v)
{
switch (v->type) {
case uiTableValueTypeString:
uiprivFree(v->u.str);
break;
}
uiprivFree(v);
}
uiTableValueType uiTableValueGetType(const uiTableValue *v)
{
return v->type;
}
uiTableValue *uiNewTableValueString(const char *str)
{
uiTableValue *v;
v = newTableValue(uiTableValueTypeString);
v->u.str = (char *) uiprivAlloc((strlen(str) + 1) * sizeof (char), "char[] (uiTableValue)");
strcpy(v->u.str, str);
return v;
}
const char *uiTableValueString(const uiTableValue *v)
{
return v->u.str;
}
uiTableValue *uiNewTableValueImage(uiImage *img)
{
uiTableValue *v;
v = newTableValue(uiTableValueTypeImage);
v->u.img = img;
return v;
}
uiImage *uiTableValueImage(const uiTableValue *v)
{
return v->u.img;
}
uiTableValue *uiNewTableValueInt(int i)
{
uiTableValue *v;
v = newTableValue(uiTableValueTypeInt);
v->u.i = i;
return v;
}
int uiTableValueInt(const uiTableValue *v)
{
return v->u.i;
}
uiTableValue *uiNewTableValueColor(double r, double g, double b, double a)
{
uiTableValue *v;
v = newTableValue(uiTableValueTypeColor);
v->u.color.r = r;
v->u.color.g = g;
v->u.color.b = b;
v->u.color.a = a;
return v;
}
void uiTableValueColor(const uiTableValue *v, double *r, double *g, double *b, double *a)
{
*r = v->u.color.r;
*g = v->u.color.g;
*b = v->u.color.b;
*a = v->u.color.a;
}
+67
View File
@@ -0,0 +1,67 @@
// 6 april 2015
// note: this file should not include ui.h, as the OS-specific ui_*.h files are included between that one and this one in the OS-specific uipriv_*.h* files
#include <stdarg.h>
#include <string.h>
#include "controlsigs.h"
#include "utf.h"
#ifdef __cplusplus
extern "C" {
#endif
// OS-specific init.* or main.* files
extern uiInitOptions uiprivOptions;
// OS-specific alloc.* files
extern void *uiprivAlloc(size_t, const char *);
#define uiprivNew(T) ((T *) uiprivAlloc(sizeof (T), #T))
extern void *uiprivRealloc(void *, size_t, const char *);
extern void uiprivFree(void *);
// debug.c and OS-specific debug.* files
// TODO get rid of this mess...
// ugh, __func__ was only introduced in MSVC 2015...
#ifdef _MSC_VER
#define uiprivMacro__func__ __FUNCTION__
#else
#define uiprivMacro__func__ __func__
#endif
extern void uiprivRealBug(const char *file, const char *line, const char *func, const char *prefix, const char *format, va_list ap);
#define uiprivMacro_ns2(s) #s
#define uiprivMacro_ns(s) uiprivMacro_ns2(s)
extern void uiprivDoImplBug(const char *file, const char *line, const char *func, const char *format, ...);
#define uiprivImplBug(...) uiprivDoImplBug(__FILE__, uiprivMacro_ns(__LINE__), uiprivMacro__func__, __VA_ARGS__)
extern void uiprivDoUserBug(const char *file, const char *line, const char *func, const char *format, ...);
#define uiprivUserBug(...) uiprivDoUserBug(__FILE__, uiprivMacro_ns(__LINE__), uiprivMacro__func__, __VA_ARGS__)
// shouldquit.c
extern int uiprivShouldQuit(void);
// areaevents.c
typedef struct uiprivClickCounter uiprivClickCounter;
// you should call Reset() to zero-initialize a new instance
// it doesn't matter that all the non-count fields are zero: the first click will fail the curButton test straightaway, so it'll return 1 and set the rest of the structure accordingly
struct uiprivClickCounter {
int curButton;
int rectX0;
int rectY0;
int rectX1;
int rectY1;
uintptr_t prevTime;
int count;
};
extern int uiprivClickCounterClick(uiprivClickCounter *c, int button, int x, int y, uintptr_t time, uintptr_t maxTime, int32_t xdist, int32_t ydist);
extern void uiprivClickCounterReset(uiprivClickCounter *);
extern int uiprivFromScancode(uintptr_t, uiAreaKeyEvent *);
// matrix.c
extern void uiprivFallbackSkew(uiDrawMatrix *, double, double, double, double);
extern void uiprivScaleCenter(double, double, double *, double *);
extern void uiprivFallbackTransformSize(uiDrawMatrix *, double *, double *);
// OS-specific text.* files
extern int uiprivStricmp(const char *a, const char *b);
#ifdef __cplusplus
}
#endif
+8
View File
@@ -0,0 +1,8 @@
// 22 may 2016
#include "../ui.h"
#include "uipriv.h"
void uiUserBugCannotSetParentOnToplevel(const char *type)
{
uiprivUserBug("You cannot make a %s a child of another uiControl,", type);
}
+348
View File
@@ -0,0 +1,348 @@
// utf by pietro gagliardi (andlabs) — https://github.com/andlabs/utf/
// 10 november 2016
// function names have been altered to avoid namespace collisions in libui static builds (see utf.h)
#include "utf.h"
// this code imitates Go's unicode/utf8 and unicode/utf16
// the biggest difference is that a rune is unsigned instead of signed (because Go guarantees what a right shift on a signed number will do, whereas C does not)
// it is also an imitation so we can license it under looser terms than the Go source
#define badrune 0xFFFD
// encoded must be at most 4 bytes
// TODO clean this code up somehow
size_t uiprivUTF8EncodeRune(uint32_t rune, char *encoded)
{
uint8_t b, c, d, e;
size_t n;
// not in the valid range for Unicode
if (rune > 0x10FFFF)
rune = badrune;
// surrogate runes cannot be encoded
if (rune >= 0xD800 && rune < 0xE000)
rune = badrune;
if (rune < 0x80) { // ASCII bytes represent themselves
b = (uint8_t) (rune & 0xFF);
n = 1;
goto done;
}
if (rune < 0x800) { // two-byte encoding
c = (uint8_t) (rune & 0x3F);
c |= 0x80;
rune >>= 6;
b = (uint8_t) (rune & 0x1F);
b |= 0xC0;
n = 2;
goto done;
}
if (rune < 0x10000) { // three-byte encoding
d = (uint8_t) (rune & 0x3F);
d |= 0x80;
rune >>= 6;
c = (uint8_t) (rune & 0x3F);
c |= 0x80;
rune >>= 6;
b = (uint8_t) (rune & 0x0F);
b |= 0xE0;
n = 3;
goto done;
}
// otherwise use a four-byte encoding
e = (uint8_t) (rune & 0x3F);
e |= 0x80;
rune >>= 6;
d = (uint8_t) (rune & 0x3F);
d |= 0x80;
rune >>= 6;
c = (uint8_t) (rune & 0x3F);
c |= 0x80;
rune >>= 6;
b = (uint8_t) (rune & 0x07);
b |= 0xF0;
n = 4;
done:
encoded[0] = b;
if (n > 1)
encoded[1] = c;
if (n > 2)
encoded[2] = d;
if (n > 3)
encoded[3] = e;
return n;
}
const char *uiprivUTF8DecodeRune(const char *s, size_t nElem, uint32_t *rune)
{
uint8_t b, c;
uint8_t lowestAllowed, highestAllowed;
size_t i, expected;
int bad;
b = (uint8_t) (*s);
if (b < 0x80) { // ASCII bytes represent themselves
*rune = b;
s++;
return s;
}
// 0xC0 and 0xC1 cover 2-byte overlong equivalents
// 0xF5 to 0xFD cover values > 0x10FFFF
// 0xFE and 0xFF were never defined (always illegal)
if (b < 0xC2 || b > 0xF4) { // invalid
*rune = badrune;
s++;
return s;
}
// this determines the range of allowed first continuation bytes
lowestAllowed = 0x80;
highestAllowed = 0xBF;
switch (b) {
case 0xE0:
// disallow 3-byte overlong equivalents
lowestAllowed = 0xA0;
break;
case 0xED:
// disallow surrogate characters
highestAllowed = 0x9F;
break;
case 0xF0:
// disallow 4-byte overlong equivalents
lowestAllowed = 0x90;
break;
case 0xF4:
// disallow values > 0x10FFFF
highestAllowed = 0x8F;
break;
}
// and this determines how many continuation bytes are expected
expected = 1;
if (b >= 0xE0)
expected++;
if (b >= 0xF0)
expected++;
if (nElem != 0) { // are there enough bytes?
nElem--;
if (nElem < expected) { // nope
*rune = badrune;
s++;
return s;
}
}
// ensure that everything is correct
// if not, **only** consume the initial byte
bad = 0;
for (i = 0; i < expected; i++) {
c = (uint8_t) (s[1 + i]);
if (c < lowestAllowed || c > highestAllowed) {
bad = 1;
break;
}
// the old lowestAllowed and highestAllowed is only for the first continuation byte
lowestAllowed = 0x80;
highestAllowed = 0xBF;
}
if (bad) {
*rune = badrune;
s++;
return s;
}
// now do the topmost bits
if (b < 0xE0)
*rune = b & 0x1F;
else if (b < 0xF0)
*rune = b & 0x0F;
else
*rune = b & 0x07;
s++; // we can finally move on
// now do the continuation bytes
for (; expected; expected--) {
c = (uint8_t) (*s);
s++;
c &= 0x3F; // strip continuation bits
*rune <<= 6;
*rune |= c;
}
return s;
}
// encoded must have at most 2 elements
size_t uiprivUTF16EncodeRune(uint32_t rune, uint16_t *encoded)
{
uint16_t low, high;
// not in the valid range for Unicode
if (rune > 0x10FFFF)
rune = badrune;
// surrogate runes cannot be encoded
if (rune >= 0xD800 && rune < 0xE000)
rune = badrune;
if (rune < 0x10000) {
encoded[0] = (uint16_t) rune;
return 1;
}
rune -= 0x10000;
low = (uint16_t) (rune & 0x3FF);
rune >>= 10;
high = (uint16_t) (rune & 0x3FF);
encoded[0] = high | 0xD800;
encoded[1] = low | 0xDC00;
return 2;
}
// TODO see if this can be cleaned up somehow
const uint16_t *uiprivUTF16DecodeRune(const uint16_t *s, size_t nElem, uint32_t *rune)
{
uint16_t high, low;
if (*s < 0xD800 || *s >= 0xE000) {
// self-representing character
*rune = *s;
s++;
return s;
}
if (*s >= 0xDC00) {
// out-of-order surrogates
*rune = badrune;
s++;
return s;
}
if (nElem == 1) { // not enough elements
*rune = badrune;
s++;
return s;
}
high = *s;
high &= 0x3FF;
if (s[1] < 0xDC00 || s[1] >= 0xE000) {
// bad surrogate pair
*rune = badrune;
s++;
return s;
}
s++;
low = *s;
s++;
low &= 0x3FF;
*rune = high;
*rune <<= 10;
*rune |= low;
*rune += 0x10000;
return s;
}
// TODO find a way to reduce the code in all of these somehow
// TODO find a way to remove u as well
size_t uiprivUTF8RuneCount(const char *s, size_t nElem)
{
size_t len;
uint32_t rune;
if (nElem != 0) {
const char *t, *u;
len = 0;
t = s;
while (nElem != 0) {
u = uiprivUTF8DecodeRune(t, nElem, &rune);
len++;
nElem -= u - t;
t = u;
}
return len;
}
len = 0;
while (*s) {
s = uiprivUTF8DecodeRune(s, nElem, &rune);
len++;
}
return len;
}
size_t uiprivUTF8UTF16Count(const char *s, size_t nElem)
{
size_t len;
uint32_t rune;
uint16_t encoded[2];
if (nElem != 0) {
const char *t, *u;
len = 0;
t = s;
while (nElem != 0) {
u = uiprivUTF8DecodeRune(t, nElem, &rune);
len += uiprivUTF16EncodeRune(rune, encoded);
nElem -= u - t;
t = u;
}
return len;
}
len = 0;
while (*s) {
s = uiprivUTF8DecodeRune(s, nElem, &rune);
len += uiprivUTF16EncodeRune(rune, encoded);
}
return len;
}
size_t uiprivUTF16RuneCount(const uint16_t *s, size_t nElem)
{
size_t len;
uint32_t rune;
if (nElem != 0) {
const uint16_t *t, *u;
len = 0;
t = s;
while (nElem != 0) {
u = uiprivUTF16DecodeRune(t, nElem, &rune);
len++;
nElem -= u - t;
t = u;
}
return len;
}
len = 0;
while (*s) {
s = uiprivUTF16DecodeRune(s, nElem, &rune);
len++;
}
return len;
}
size_t uiprivUTF16UTF8Count(const uint16_t *s, size_t nElem)
{
size_t len;
uint32_t rune;
char encoded[4];
if (nElem != 0) {
const uint16_t *t, *u;
len = 0;
t = s;
while (nElem != 0) {
u = uiprivUTF16DecodeRune(t, nElem, &rune);
len += uiprivUTF8EncodeRune(rune, encoded);
nElem -= u - t;
t = u;
}
return len;
}
len = 0;
while (*s) {
s = uiprivUTF16DecodeRune(s, nElem, &rune);
len += uiprivUTF8EncodeRune(rune, encoded);
}
return len;
}
+105
View File
@@ -0,0 +1,105 @@
// utf by pietro gagliardi (andlabs) — https://github.com/andlabs/utf/
// 10 november 2016
// note the overridden names with uipriv at the beginning; this avoids potential symbol clashes when building libui as a static library
// LONGTERM find a way to encode the name overrides directly into the utf library
#ifdef __cplusplus
extern "C" {
#endif
// TODO (for utf itself as well) should this go outside the extern "C" block or not
#include <stddef.h>
#include <stdint.h>
// if nElem == 0, assume the buffer has no upper limit and is '\0' terminated
// otherwise, assume buffer is NOT '\0' terminated but is bounded by nElem *elements*
extern size_t uiprivUTF8EncodeRune(uint32_t rune, char *encoded);
extern const char *uiprivUTF8DecodeRune(const char *s, size_t nElem, uint32_t *rune);
extern size_t uiprivUTF16EncodeRune(uint32_t rune, uint16_t *encoded);
extern const uint16_t *uiprivUTF16DecodeRune(const uint16_t *s, size_t nElem, uint32_t *rune);
extern size_t uiprivUTF8RuneCount(const char *s, size_t nElem);
extern size_t uiprivUTF8UTF16Count(const char *s, size_t nElem);
extern size_t uiprivUTF16RuneCount(const uint16_t *s, size_t nElem);
extern size_t uiprivUTF16UTF8Count(const uint16_t *s, size_t nElem);
#ifdef __cplusplus
}
// TODO sync this back to upstream (need copyright clearance first)
// On Windows, wchar_t is equivalent to uint16_t, but C++ requires
// wchar_t to be a completely distinct type. These overloads allow
// passing wchar_t pointers directly into these functions from C++
// on Windows. Otherwise, you'd need to cast to pass a wchar_t
// pointer, WCHAR pointer, or equivalent to these functions.
//
// This does not apply to MSVC because the situation there is
// slightly more complicated; see below.
#if defined(_WIN32) && !defined(_MSC_VER)
inline size_t uiprivUTF16EncodeRune(uint32_t rune, wchar_t *encoded)
{
return uiprivUTF16EncodeRune(rune, reinterpret_cast<uint16_t *>(encoded));
}
inline const wchar_t *uiprivUTF16DecodeRune(const wchar_t *s, size_t nElem, uint32_t *rune)
{
const uint16_t *ret;
ret = uiprivUTF16DecodeRune(reinterpret_cast<const uint16_t *>(s), nElem, rune);
return reinterpret_cast<const wchar_t *>(ret);
}
inline size_t uiprivUTF16RuneCount(const wchar_t *s, size_t nElem)
{
return uiprivUTF16RuneCount(reinterpret_cast<const uint16_t *>(s), nElem);
}
inline size_t uiprivUTF16UTF8Count(const wchar_t *s, size_t nElem)
{
return uiprivUTF16UTF8Count(reinterpret_cast<const uint16_t *>(s), nElem);
}
#endif
// This is the same as the above, except that with MSVC, whether
// wchar_t is a keyword or not is controlled by a compiler option!
// (At least with gcc, this is not the case; thanks redi in
// irc.freenode.net/#gcc.) We use __wchar_t to be independent of
// the option; see https://blogs.msdn.microsoft.com/oldnewthing/20161201-00/?p=94836
// (ironically posted one day after I initially wrote this code!).
// TODO should defined(_WIN32) be used too?
// TODO check this under /Wall
// TODO are C-style casts enough? or will that fail in /Wall?
// TODO same for UniChar/unichar on Mac? if both are unsigned then we have nothing to worry about
#if defined(_MSC_VER)
inline size_t uiprivUTF16EncodeRune(uint32_t rune, __wchar_t *encoded)
{
return uiprivUTF16EncodeRune(rune, reinterpret_cast<uint16_t *>(encoded));
}
inline const __wchar_t *uiprivUTF16DecodeRune(const __wchar_t *s, size_t nElem, uint32_t *rune)
{
const uint16_t *ret;
ret = uiprivUTF16DecodeRune(reinterpret_cast<const uint16_t *>(s), nElem, rune);
return reinterpret_cast<const __wchar_t *>(ret);
}
inline size_t uiprivUTF16RuneCount(const __wchar_t *s, size_t nElem)
{
return uiprivUTF16RuneCount(reinterpret_cast<const uint16_t *>(s), nElem);
}
inline size_t uiprivUTF16UTF8Count(const __wchar_t *s, size_t nElem)
{
return uiprivUTF16UTF8Count(reinterpret_cast<const uint16_t *>(s), nElem);
}
#endif
#endif