Started implementing the new text layout stuff on GTK+. The drawtext example works.
This commit is contained in:
parent
7f270942a7
commit
5444f76bd3
|
@ -117,6 +117,7 @@ int main(void)
|
||||||
uiWindowOnClosing(mainwin, onClosing, NULL);
|
uiWindowOnClosing(mainwin, onClosing, NULL);
|
||||||
|
|
||||||
area = uiNewArea(&handler);
|
area = uiNewArea(&handler);
|
||||||
|
// TODO on GTK+ this doesn't get expand properties set properly?
|
||||||
uiWindowSetChild(mainwin, uiControl(area));
|
uiWindowSetChild(mainwin, uiControl(area));
|
||||||
|
|
||||||
uiControlShow(uiControl(mainwin));
|
uiControlShow(uiControl(mainwin));
|
||||||
|
|
|
@ -22,7 +22,7 @@ list(APPEND _LIBUI_SOURCES
|
||||||
unix/drawtext.c
|
unix/drawtext.c
|
||||||
unix/editablecombo.c
|
unix/editablecombo.c
|
||||||
unix/entry.c
|
unix/entry.c
|
||||||
unix/fontbutton.c
|
# unix/fontbutton.c
|
||||||
unix/form.c
|
unix/form.c
|
||||||
unix/future.c
|
unix/future.c
|
||||||
unix/graphemes.c
|
unix/graphemes.c
|
||||||
|
|
|
@ -0,0 +1,217 @@
|
||||||
|
// 6 september 2015
|
||||||
|
#include "uipriv_unix.h"
|
||||||
|
#include "draw.h"
|
||||||
|
|
||||||
|
struct uiDrawFontFamilies {
|
||||||
|
PangoFontFamily **f;
|
||||||
|
int n;
|
||||||
|
};
|
||||||
|
|
||||||
|
uiDrawFontFamilies *uiDrawListFontFamilies(void)
|
||||||
|
{
|
||||||
|
uiDrawFontFamilies *ff;
|
||||||
|
PangoFontMap *map;
|
||||||
|
|
||||||
|
ff = uiNew(uiDrawFontFamilies);
|
||||||
|
map = pango_cairo_font_map_get_default();
|
||||||
|
pango_font_map_list_families(map, &(ff->f), &(ff->n));
|
||||||
|
// do not free map; it's a shared resource
|
||||||
|
return ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff)
|
||||||
|
{
|
||||||
|
return ff->n;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, int n)
|
||||||
|
{
|
||||||
|
PangoFontFamily *f;
|
||||||
|
|
||||||
|
f = ff->f[n];
|
||||||
|
return uiUnixStrdupText(pango_font_family_get_name(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff)
|
||||||
|
{
|
||||||
|
g_free(ff->f);
|
||||||
|
uiFree(ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uiDrawTextFont {
|
||||||
|
PangoFont *f;
|
||||||
|
};
|
||||||
|
|
||||||
|
uiDrawTextFont *mkTextFont(PangoFont *f, gboolean ref)
|
||||||
|
{
|
||||||
|
uiDrawTextFont *font;
|
||||||
|
|
||||||
|
font = uiNew(uiDrawTextFont);
|
||||||
|
font->f = f;
|
||||||
|
if (ref)
|
||||||
|
g_object_ref(font->f);
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc)
|
||||||
|
{
|
||||||
|
PangoFont *f;
|
||||||
|
PangoContext *context;
|
||||||
|
|
||||||
|
// in this case, the context is necessary for the metrics to be correct
|
||||||
|
context = mkGenericPangoCairoContext();
|
||||||
|
f = pango_font_map_load_font(pango_cairo_font_map_get_default(), context, pdesc);
|
||||||
|
if (f == NULL) {
|
||||||
|
// LONGTERM
|
||||||
|
g_error("[libui] no match in pangoDescToPangoFont(); report to andlabs");
|
||||||
|
}
|
||||||
|
g_object_unref(context);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
uiDrawTextFont *uiDrawLoadClosestFont(const uiDrawTextFontDescriptor *desc)
|
||||||
|
{
|
||||||
|
PangoFont *f;
|
||||||
|
PangoFontDescription *pdesc;
|
||||||
|
|
||||||
|
pdesc = pango_font_description_new();
|
||||||
|
pango_font_description_set_family(pdesc,
|
||||||
|
desc->Family);
|
||||||
|
pango_font_description_set_size(pdesc,
|
||||||
|
(gint) (desc->Size * PANGO_SCALE));
|
||||||
|
pango_font_description_set_weight(pdesc,
|
||||||
|
pangoWeights[desc->Weight]);
|
||||||
|
pango_font_description_set_style(pdesc,
|
||||||
|
pangoItalics[desc->Italic]);
|
||||||
|
pango_font_description_set_stretch(pdesc,
|
||||||
|
pangoStretches[desc->Stretch]);
|
||||||
|
f = pangoDescToPangoFont(pdesc);
|
||||||
|
pango_font_description_free(pdesc);
|
||||||
|
return mkTextFont(f, FALSE); // we hold the initial reference; no need to ref
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawFreeTextFont(uiDrawTextFont *font)
|
||||||
|
{
|
||||||
|
g_object_unref(font->f);
|
||||||
|
uiFree(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t uiDrawTextFontHandle(uiDrawTextFont *font)
|
||||||
|
{
|
||||||
|
return (uintptr_t) (font->f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawTextFontDescribe(uiDrawTextFont *font, uiDrawTextFontDescriptor *desc)
|
||||||
|
{
|
||||||
|
PangoFontDescription *pdesc;
|
||||||
|
|
||||||
|
// this creates a copy; we free it later
|
||||||
|
pdesc = pango_font_describe(font->f);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
pango_font_description_free(pdesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://developer.gnome.org/pango/1.30/pango-Cairo-Rendering.html#pango-Cairo-Rendering.description
|
||||||
|
// Note that we convert to double before dividing to make sure the floating-point stuff is right
|
||||||
|
#define pangoToCairo(pango) (((double) (pango)) / PANGO_SCALE)
|
||||||
|
#define cairoToPango(cairo) ((gint) ((cairo) * PANGO_SCALE))
|
||||||
|
|
||||||
|
void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metrics)
|
||||||
|
{
|
||||||
|
PangoFontMetrics *pm;
|
||||||
|
|
||||||
|
pm = pango_font_get_metrics(font->f, NULL);
|
||||||
|
metrics->Ascent = pangoToCairo(pango_font_metrics_get_ascent(pm));
|
||||||
|
metrics->Descent = pangoToCairo(pango_font_metrics_get_descent(pm));
|
||||||
|
// Pango doesn't seem to expose this :( Use 0 and hope for the best.
|
||||||
|
metrics->Leading = 0;
|
||||||
|
metrics->UnderlinePos = pangoToCairo(pango_font_metrics_get_underline_position(pm));
|
||||||
|
metrics->UnderlineThickness = pangoToCairo(pango_font_metrics_get_underline_thickness(pm));
|
||||||
|
pango_font_metrics_unref(pm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: PangoCairoLayouts are tied to a given cairo_t, so we can't store one in this device-independent structure
|
||||||
|
struct uiDrawTextLayout {
|
||||||
|
char *s;
|
||||||
|
ptrdiff_t *graphemes;
|
||||||
|
PangoFont *defaultFont;
|
||||||
|
double width;
|
||||||
|
PangoAttrList *attrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultFont, double width)
|
||||||
|
{
|
||||||
|
uiDrawTextLayout *layout;
|
||||||
|
PangoContext *context;
|
||||||
|
|
||||||
|
layout = uiNew(uiDrawTextLayout);
|
||||||
|
layout->s = g_strdup(text);
|
||||||
|
context = mkGenericPangoCairoContext();
|
||||||
|
layout->graphemes = graphemes(layout->s, context);
|
||||||
|
g_object_unref(context);
|
||||||
|
layout->defaultFont = defaultFont->f;
|
||||||
|
g_object_ref(layout->defaultFont); // retain a copy
|
||||||
|
uiDrawTextLayoutSetWidth(layout, width);
|
||||||
|
layout->attrs = pango_attr_list_new();
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawFreeTextLayout(uiDrawTextLayout *layout)
|
||||||
|
{
|
||||||
|
pango_attr_list_unref(layout->attrs);
|
||||||
|
g_object_unref(layout->defaultFont);
|
||||||
|
uiFree(layout->graphemes);
|
||||||
|
g_free(layout->s);
|
||||||
|
uiFree(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width)
|
||||||
|
{
|
||||||
|
layout->width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prepareLayout(uiDrawTextLayout *layout, PangoLayout *pl)
|
||||||
|
{
|
||||||
|
// again, this makes a copy
|
||||||
|
desc = pango_font_describe(layout->defaultFont);
|
||||||
|
|
||||||
|
pango_layout_set_attributes(pl, layout->attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout)
|
||||||
|
{
|
||||||
|
PangoLayout *pl;
|
||||||
|
|
||||||
|
pl = pango_cairo_create_layout(c->cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addAttr(uiDrawTextLayout *layout, PangoAttribute *attr, int startChar, int endChar)
|
||||||
|
{
|
||||||
|
attr->start_index = layout->graphemes[startChar];
|
||||||
|
attr->end_index = layout->graphemes[endChar];
|
||||||
|
pango_attr_list_insert(layout->attrs, attr);
|
||||||
|
// pango_attr_list_insert() takes attr; we don't free it
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a)
|
||||||
|
{
|
||||||
|
PangoAttribute *attr;
|
||||||
|
guint16 rr, gg, bb, aa;
|
||||||
|
|
||||||
|
rr = (guint16) (r * 65535);
|
||||||
|
gg = (guint16) (g * 65535);
|
||||||
|
bb = (guint16) (b * 65535);
|
||||||
|
aa = (guint16) (a * 65535);
|
||||||
|
|
||||||
|
attr = pango_attr_foreground_new(rr, gg, bb);
|
||||||
|
addAttr(layout, attr, startChar, endChar);
|
||||||
|
|
||||||
|
// TODO what if aa == 0?
|
||||||
|
attr = FUTURE_pango_attr_foreground_alpha_new(aa);
|
||||||
|
if (attr != NULL)
|
||||||
|
addAttr(layout, attr, startChar, endChar);
|
||||||
|
}
|
339
unix/drawtext.c
339
unix/drawtext.c
|
@ -1,71 +1,21 @@
|
||||||
// 6 september 2015
|
// 17 january 2017
|
||||||
#include "uipriv_unix.h"
|
#include "uipriv_unix.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
struct uiDrawFontFamilies {
|
struct uiDrawTextLayout {
|
||||||
PangoFontFamily **f;
|
PangoLayout *layout;
|
||||||
int n;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uiDrawFontFamilies *uiDrawListFontFamilies(void)
|
// See https://developer.gnome.org/pango/1.30/pango-Cairo-Rendering.html#pango-Cairo-Rendering.description
|
||||||
{
|
// For the conversion, see https://developer.gnome.org/pango/1.30/pango-Glyph-Storage.html#pango-units-to-double and https://developer.gnome.org/pango/1.30/pango-Glyph-Storage.html#pango-units-from-double
|
||||||
uiDrawFontFamilies *ff;
|
#define pangoToCairo(pango) (pango_units_to_double(pango))
|
||||||
PangoFontMap *map;
|
#define cairoToPango(cairo) (pango_units_from_double(cairo))
|
||||||
|
|
||||||
ff = uiNew(uiDrawFontFamilies);
|
// we need a context for a few things
|
||||||
map = pango_cairo_font_map_get_default();
|
// the documentation suggests creating cairo_t-specific, GdkScreen-specific, or even GtkWidget-specific contexts, but we can't really do that because we want our uiDrawTextFonts and uiDrawTextLayouts to be context-independent
|
||||||
pango_font_map_list_families(map, &(ff->f), &(ff->n));
|
// we could use pango_font_map_create_context(pango_cairo_font_map_get_default()) but that will ignore GDK-specific settings
|
||||||
// do not free map; it's a shared resource
|
// so let's use gdk_pango_context_get() instead; even though it's for the default screen only, it's good enough for us
|
||||||
return ff;
|
#define mkGenericPangoCairoContext() (gdk_pango_context_get())
|
||||||
}
|
|
||||||
|
|
||||||
int uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff)
|
|
||||||
{
|
|
||||||
return ff->n;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, int n)
|
|
||||||
{
|
|
||||||
PangoFontFamily *f;
|
|
||||||
|
|
||||||
f = ff->f[n];
|
|
||||||
return uiUnixStrdupText(pango_font_family_get_name(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff)
|
|
||||||
{
|
|
||||||
g_free(ff->f);
|
|
||||||
uiFree(ff);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct uiDrawTextFont {
|
|
||||||
PangoFont *f;
|
|
||||||
};
|
|
||||||
|
|
||||||
uiDrawTextFont *mkTextFont(PangoFont *f, gboolean ref)
|
|
||||||
{
|
|
||||||
uiDrawTextFont *font;
|
|
||||||
|
|
||||||
font = uiNew(uiDrawTextFont);
|
|
||||||
font->f = f;
|
|
||||||
if (ref)
|
|
||||||
g_object_ref(font->f);
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const PangoWeight pangoWeights[] = {
|
|
||||||
[uiDrawTextWeightThin] = PANGO_WEIGHT_THIN,
|
|
||||||
[uiDrawTextWeightUltraLight] = PANGO_WEIGHT_ULTRALIGHT,
|
|
||||||
[uiDrawTextWeightLight] = PANGO_WEIGHT_LIGHT,
|
|
||||||
[uiDrawTextWeightBook] = PANGO_WEIGHT_BOOK,
|
|
||||||
[uiDrawTextWeightNormal] = PANGO_WEIGHT_NORMAL,
|
|
||||||
[uiDrawTextWeightMedium] = PANGO_WEIGHT_MEDIUM,
|
|
||||||
[uiDrawTextWeightSemiBold] = PANGO_WEIGHT_SEMIBOLD,
|
|
||||||
[uiDrawTextWeightBold] = PANGO_WEIGHT_BOLD,
|
|
||||||
[uiDrawTextWeightUltraBold] = PANGO_WEIGHT_ULTRABOLD,
|
|
||||||
[uiDrawTextWeightHeavy] = PANGO_WEIGHT_HEAVY,
|
|
||||||
[uiDrawTextWeightUltraHeavy] = PANGO_WEIGHT_ULTRAHEAVY,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const PangoStyle pangoItalics[] = {
|
static const PangoStyle pangoItalics[] = {
|
||||||
[uiDrawTextItalicNormal] = PANGO_STYLE_NORMAL,
|
[uiDrawTextItalicNormal] = PANGO_STYLE_NORMAL,
|
||||||
|
@ -85,209 +35,112 @@ static const PangoStretch pangoStretches[] = {
|
||||||
[uiDrawTextStretchUltraExpanded] = PANGO_STRETCH_ULTRA_EXPANDED,
|
[uiDrawTextStretchUltraExpanded] = PANGO_STRETCH_ULTRA_EXPANDED,
|
||||||
};
|
};
|
||||||
|
|
||||||
// we need a context for a few things
|
uiDrawTextLayout *uiDrawNewTextLayout(uiAttributedString *s, uiDrawFontDescriptor *defaultFont, double width)
|
||||||
// the documentation suggests creating cairo_t-specific, GdkScreen-specific, or even GtkWidget-specific contexts, but we can't really do that because we want our uiDrawTextFonts and uiDrawTextLayouts to be context-independent
|
|
||||||
// we could use pango_font_map_create_context(pango_cairo_font_map_get_default()) but that will ignore GDK-specific settings
|
|
||||||
// so let's use gdk_pango_context_get() instead; even though it's for the default screen only, it's good enough for us
|
|
||||||
#define mkGenericPangoCairoContext() (gdk_pango_context_get())
|
|
||||||
|
|
||||||
PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc)
|
|
||||||
{
|
{
|
||||||
PangoFont *f;
|
uiDrawTextLayout *tl;
|
||||||
PangoContext *context;
|
PangoContext *context;
|
||||||
|
|
||||||
// in this case, the context is necessary for the metrics to be correct
|
|
||||||
context = mkGenericPangoCairoContext();
|
|
||||||
f = pango_font_map_load_font(pango_cairo_font_map_get_default(), context, pdesc);
|
|
||||||
if (f == NULL) {
|
|
||||||
// LONGTERM
|
|
||||||
g_error("[libui] no match in pangoDescToPangoFont(); report to andlabs");
|
|
||||||
}
|
|
||||||
g_object_unref(context);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
uiDrawTextFont *uiDrawLoadClosestFont(const uiDrawTextFontDescriptor *desc)
|
|
||||||
{
|
|
||||||
PangoFont *f;
|
|
||||||
PangoFontDescription *pdesc;
|
|
||||||
|
|
||||||
pdesc = pango_font_description_new();
|
|
||||||
pango_font_description_set_family(pdesc,
|
|
||||||
desc->Family);
|
|
||||||
pango_font_description_set_size(pdesc,
|
|
||||||
(gint) (desc->Size * PANGO_SCALE));
|
|
||||||
pango_font_description_set_weight(pdesc,
|
|
||||||
pangoWeights[desc->Weight]);
|
|
||||||
pango_font_description_set_style(pdesc,
|
|
||||||
pangoItalics[desc->Italic]);
|
|
||||||
pango_font_description_set_stretch(pdesc,
|
|
||||||
pangoStretches[desc->Stretch]);
|
|
||||||
f = pangoDescToPangoFont(pdesc);
|
|
||||||
pango_font_description_free(pdesc);
|
|
||||||
return mkTextFont(f, FALSE); // we hold the initial reference; no need to ref
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiDrawFreeTextFont(uiDrawTextFont *font)
|
|
||||||
{
|
|
||||||
g_object_unref(font->f);
|
|
||||||
uiFree(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t uiDrawTextFontHandle(uiDrawTextFont *font)
|
|
||||||
{
|
|
||||||
return (uintptr_t) (font->f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiDrawTextFontDescribe(uiDrawTextFont *font, uiDrawTextFontDescriptor *desc)
|
|
||||||
{
|
|
||||||
PangoFontDescription *pdesc;
|
|
||||||
|
|
||||||
// this creates a copy; we free it later
|
|
||||||
pdesc = pango_font_describe(font->f);
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
pango_font_description_free(pdesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// See https://developer.gnome.org/pango/1.30/pango-Cairo-Rendering.html#pango-Cairo-Rendering.description
|
|
||||||
// Note that we convert to double before dividing to make sure the floating-point stuff is right
|
|
||||||
#define pangoToCairo(pango) (((double) (pango)) / PANGO_SCALE)
|
|
||||||
#define cairoToPango(cairo) ((gint) ((cairo) * PANGO_SCALE))
|
|
||||||
|
|
||||||
void uiDrawTextFontGetMetrics(uiDrawTextFont *font, uiDrawTextFontMetrics *metrics)
|
|
||||||
{
|
|
||||||
PangoFontMetrics *pm;
|
|
||||||
|
|
||||||
pm = pango_font_get_metrics(font->f, NULL);
|
|
||||||
metrics->Ascent = pangoToCairo(pango_font_metrics_get_ascent(pm));
|
|
||||||
metrics->Descent = pangoToCairo(pango_font_metrics_get_descent(pm));
|
|
||||||
// Pango doesn't seem to expose this :( Use 0 and hope for the best.
|
|
||||||
metrics->Leading = 0;
|
|
||||||
metrics->UnderlinePos = pangoToCairo(pango_font_metrics_get_underline_position(pm));
|
|
||||||
metrics->UnderlineThickness = pangoToCairo(pango_font_metrics_get_underline_thickness(pm));
|
|
||||||
pango_font_metrics_unref(pm);
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: PangoCairoLayouts are tied to a given cairo_t, so we can't store one in this device-independent structure
|
|
||||||
struct uiDrawTextLayout {
|
|
||||||
char *s;
|
|
||||||
ptrdiff_t *graphemes;
|
|
||||||
PangoFont *defaultFont;
|
|
||||||
double width;
|
|
||||||
PangoAttrList *attrs;
|
|
||||||
};
|
|
||||||
|
|
||||||
uiDrawTextLayout *uiDrawNewTextLayout(const char *text, uiDrawTextFont *defaultFont, double width)
|
|
||||||
{
|
|
||||||
uiDrawTextLayout *layout;
|
|
||||||
PangoContext *context;
|
|
||||||
|
|
||||||
layout = uiNew(uiDrawTextLayout);
|
|
||||||
layout->s = g_strdup(text);
|
|
||||||
context = mkGenericPangoCairoContext();
|
|
||||||
layout->graphemes = graphemes(layout->s, context);
|
|
||||||
g_object_unref(context);
|
|
||||||
layout->defaultFont = defaultFont->f;
|
|
||||||
g_object_ref(layout->defaultFont); // retain a copy
|
|
||||||
uiDrawTextLayoutSetWidth(layout, width);
|
|
||||||
layout->attrs = pango_attr_list_new();
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiDrawFreeTextLayout(uiDrawTextLayout *layout)
|
|
||||||
{
|
|
||||||
pango_attr_list_unref(layout->attrs);
|
|
||||||
g_object_unref(layout->defaultFont);
|
|
||||||
uiFree(layout->graphemes);
|
|
||||||
g_free(layout->s);
|
|
||||||
uiFree(layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiDrawTextLayoutSetWidth(uiDrawTextLayout *layout, double width)
|
|
||||||
{
|
|
||||||
layout->width = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prepareLayout(uiDrawTextLayout *layout, PangoLayout *pl)
|
|
||||||
{
|
|
||||||
PangoFontDescription *desc;
|
PangoFontDescription *desc;
|
||||||
int width;
|
int pangoWidth;
|
||||||
|
|
||||||
pango_layout_set_text(pl, layout->s, -1);
|
tl = uiNew(uiDrawTextLayout);
|
||||||
|
|
||||||
// again, this makes a copy
|
|
||||||
desc = pango_font_describe(layout->defaultFont);
|
|
||||||
// this is safe; the description is copied
|
|
||||||
pango_layout_set_font_description(pl, desc);
|
|
||||||
pango_font_description_free(desc);
|
|
||||||
|
|
||||||
width = cairoToPango(layout->width);
|
|
||||||
if (layout->width < 0)
|
|
||||||
width = -1;
|
|
||||||
pango_layout_set_width(pl, width);
|
|
||||||
|
|
||||||
pango_layout_set_attributes(pl, layout->attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uiDrawTextLayoutExtents(uiDrawTextLayout *layout, double *width, double *height)
|
|
||||||
{
|
|
||||||
PangoContext *context;
|
|
||||||
PangoLayout *pl;
|
|
||||||
PangoRectangle logical;
|
|
||||||
|
|
||||||
// in this case, the context is necessary to create the layout
|
// in this case, the context is necessary to create the layout
|
||||||
// the layout takes a ref on the context so we can unref it afterward
|
// the layout takes a ref on the context so we can unref it afterward
|
||||||
context = mkGenericPangoCairoContext();
|
context = mkGenericPangoCairoContext();
|
||||||
pl = pango_layout_new(context);
|
tl->layout = pango_layout_new(context);
|
||||||
g_object_unref(context);
|
g_object_unref(context);
|
||||||
prepareLayout(layout, pl);
|
|
||||||
|
|
||||||
pango_layout_get_extents(pl, NULL, &logical);
|
// this is safe; pango_layout_set_text() copies the string
|
||||||
|
pango_layout_set_text(tl->layout, uiAttributedStringString(s), -1);
|
||||||
|
|
||||||
g_object_unref(pl);
|
desc = pango_font_description_new();
|
||||||
|
pango_font_description_set_family(desc, defaultFont->Family);
|
||||||
|
pango_font_description_set_style(desc, pangoItalics[defaultFont->Italic]);
|
||||||
|
// for the most part, pango weights correlate to ours
|
||||||
|
// the differences:
|
||||||
|
// - Book — libui: 350, Pango: 380
|
||||||
|
// - Ultra Heavy — libui: 950, Pango: 1000
|
||||||
|
// TODO figure out what to do about this misalignment
|
||||||
|
pango_font_description_set_weight(desc, defaultFont->Weight);
|
||||||
|
pango_font_description_set_stretch(desc, pangoStretches[defaultFont->Stretch]);
|
||||||
|
// see https://developer.gnome.org/pango/1.30/pango-Fonts.html#pango-font-description-set-size and https://developer.gnome.org/pango/1.30/pango-Glyph-Storage.html#pango-units-from-double
|
||||||
|
pango_font_description_set_size(desc, pango_units_from_double(defaultFont->Size));
|
||||||
|
pango_layout_set_font_description(tl->layout, desc);
|
||||||
|
// this is safe; the description is copied
|
||||||
|
pango_font_description_free(desc);
|
||||||
|
|
||||||
|
pangoWidth = cairoToPango(width);
|
||||||
|
if (width < 0)
|
||||||
|
pangoWidth = -1;
|
||||||
|
pango_layout_set_width(tl->layout, pangoWidth);
|
||||||
|
|
||||||
|
// TODO attributes
|
||||||
|
|
||||||
|
return tl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawFreeTextLayout(uiDrawTextLayout *tl)
|
||||||
|
{
|
||||||
|
g_object_unref(tl->layout);
|
||||||
|
uiFree(tl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawText(uiDrawContext *c, uiDrawTextLayout *tl, double x, double y)
|
||||||
|
{
|
||||||
|
cairo_move_to(c->cr, x, y);
|
||||||
|
pango_cairo_show_layout(c->cr, tl->layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawTextLayoutExtents(uiDrawTextLayout *tl, double *width, double *height)
|
||||||
|
{
|
||||||
|
PangoRectangle logical;
|
||||||
|
|
||||||
|
pango_layout_get_extents(tl->layout, NULL, &logical);
|
||||||
*width = pangoToCairo(logical.width);
|
*width = pangoToCairo(logical.width);
|
||||||
*height = pangoToCairo(logical.height);
|
*height = pangoToCairo(logical.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout)
|
int uiDrawTextLayoutNumLines(uiDrawTextLayout *tl)
|
||||||
{
|
{
|
||||||
PangoLayout *pl;
|
return pango_layout_get_line_count(tl->layout);
|
||||||
|
|
||||||
pl = pango_cairo_create_layout(c->cr);
|
|
||||||
prepareLayout(layout, pl);
|
|
||||||
|
|
||||||
cairo_move_to(c->cr, x, y);
|
|
||||||
pango_cairo_show_layout(c->cr, pl);
|
|
||||||
|
|
||||||
g_object_unref(pl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addAttr(uiDrawTextLayout *layout, PangoAttribute *attr, int startChar, int endChar)
|
void uiDrawTextLayoutLineByteRange(uiDrawTextLayout *tl, int line, size_t *start, size_t *end)
|
||||||
{
|
{
|
||||||
attr->start_index = layout->graphemes[startChar];
|
PangoLayoutLine *pll;
|
||||||
attr->end_index = layout->graphemes[endChar];
|
|
||||||
pango_attr_list_insert(layout->attrs, attr);
|
pll = pango_layout_get_line_readonly(tl->layout, line);
|
||||||
// pango_attr_list_insert() takes attr; we don't free it
|
*start = pll->start_index;
|
||||||
|
*end = pll->start_index + pll->length;
|
||||||
|
// TODO unref?
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawTextLayoutSetColor(uiDrawTextLayout *layout, int startChar, int endChar, double r, double g, double b, double a)
|
void uiDrawTextLayoutLineGetMetrics(uiDrawTextLayout *tl, int line, uiDrawTextLayoutLineMetrics *m)
|
||||||
{
|
{
|
||||||
PangoAttribute *attr;
|
PangoLayoutLine *pll;
|
||||||
guint16 rr, gg, bb, aa;
|
|
||||||
|
|
||||||
rr = (guint16) (r * 65535);
|
pll = pango_layout_get_line_readonly(tl->layout, line);
|
||||||
gg = (guint16) (g * 65535);
|
// TODO unref?
|
||||||
bb = (guint16) (b * 65535);
|
}
|
||||||
aa = (guint16) (a * 65535);
|
|
||||||
|
// TODO
|
||||||
attr = pango_attr_foreground_new(rr, gg, bb);
|
#if 0
|
||||||
addAttr(layout, attr, startChar, endChar);
|
{
|
||||||
|
PangoLayoutLine *pll;
|
||||||
// TODO what if aa == 0?
|
|
||||||
attr = FUTURE_pango_attr_foreground_alpha_new(aa);
|
pll = pango_layout_get_line_readonly(tl->layout, line);
|
||||||
if (attr != NULL)
|
// TODO unref?
|
||||||
addAttr(layout, attr, startChar, endChar);
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void uiDrawTextLayoutByteIndexToGraphemeRect(uiDrawTextLayout *tl, size_t pos, int *line, double *x, double *y, double *width, double *height)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawTextLayoutHitTest(uiDrawTextLayout *tl, double x, double y, uiDrawTextLayoutHitTestResult *result)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawTextLayoutByteRangeToRectangle(uiDrawTextLayout *tl, size_t start, size_t end, uiDrawTextLayoutByteRangeRectangle *r)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ int graphemesTakesUTF16(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct graphemes *graphemes(void *s, size_t len);
|
struct graphemes *graphemes(void *s, size_t len)
|
||||||
{
|
{
|
||||||
struct graphemes *g;
|
struct graphemes *g;
|
||||||
char *text = (char *) s;
|
char *text = (char *) s;
|
||||||
|
|
|
@ -46,8 +46,10 @@ extern uiDrawContext *newContext(cairo_t *);
|
||||||
extern void freeContext(uiDrawContext *);
|
extern void freeContext(uiDrawContext *);
|
||||||
|
|
||||||
// drawtext.c
|
// drawtext.c
|
||||||
|
#if 0 /* TODO */
|
||||||
extern uiDrawTextFont *mkTextFont(PangoFont *f, gboolean add);
|
extern uiDrawTextFont *mkTextFont(PangoFont *f, gboolean add);
|
||||||
extern PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc);
|
extern PangoFont *pangoDescToPangoFont(PangoFontDescription *pdesc);
|
||||||
|
#endif
|
||||||
|
|
||||||
// image.c
|
// image.c
|
||||||
/*TODO remove this*/typedef struct uiImage uiImage;
|
/*TODO remove this*/typedef struct uiImage uiImage;
|
||||||
|
|
Loading…
Reference in New Issue