diff --git a/build/GNUmakefile.example b/build/GNUmakefile.example index 34268a97..fab16e2b 100644 --- a/build/GNUmakefile.example +++ b/build/GNUmakefile.example @@ -15,6 +15,11 @@ CFILES += \ HFILES += \ ui.h +ifeq ($(OS),windows) +RCFILES += \ + examples/resources.rc +endif + NAME = $(EXAMPLE) SUFFIX = $(EXESUFFIX) diff --git a/darwin/checkbox.m b/darwin/checkbox.m index 28f789d8..09af33a7 100644 --- a/darwin/checkbox.m +++ b/darwin/checkbox.m @@ -75,6 +75,8 @@ void uiCheckboxSetText(uiCheckbox *c, const char *text) { [c->button setTitle:toNSString(text)]; // this may result in the size of the checkbox changing + // TODO something somewhere is causing this to corrupt some memory so that, for instance, page7b's mouseExited: never triggers on 10.11; figure out what + // TODO is this related to map-related crashes? uiDarwinControlTriggerRelayout(uiDarwinControl(c)); } diff --git a/darwin/draw.m b/darwin/draw.m index e14c5d2d..268108e5 100644 --- a/darwin/draw.m +++ b/darwin/draw.m @@ -488,3 +488,20 @@ void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff) CFRelease(ff->fonts); uiFree(ff); } + +double uiDrawTextSizeToPoints(double textSize) +{ + // TODO + return 0; +} + +double uiDrawPointsToTextSize(double points) +{ + // TODO + return 0; +} + +void uiDrawText(uiDrawContext *c, double x, double y, const char *text, uiDrawTextStyle *style) +{ + // TODO +} diff --git a/darwin/tab.m b/darwin/tab.m index 14cf44c0..b711168a 100644 --- a/darwin/tab.m +++ b/darwin/tab.m @@ -86,6 +86,7 @@ void uiTabInsertAt(uiTab *t, const char *name, uintmax_t n, uiControl *child) childView = (NSView *) uiControlHandle(child); view = [[NSView alloc] initWithFrame:NSZeroRect]; + // TODO if we turn off the autoresizing mask, nothing shows up; didn't this get documented somewhere? [view addSubview:childView]; [t->pages insertObject:[NSValue valueWithPointer:child] atIndex:n]; diff --git a/examples/example.manifest b/examples/example.manifest new file mode 100644 index 00000000..41e7c9c5 --- /dev/null +++ b/examples/example.manifest @@ -0,0 +1,20 @@ + + + +Your application description here. + + + + + + + + + + + diff --git a/examples/resources.rc b/examples/resources.rc new file mode 100644 index 00000000..b55e24ec --- /dev/null +++ b/examples/resources.rc @@ -0,0 +1,9 @@ +// 30 may 2015 + +// this is a UTF-8 file +#pragma code_page(65001) + +// this is the Common Controls 6 manifest +// TODO set up the string values here +// 1 is the value of CREATEPROCESS_MANIFEST_RESOURCE_ID and 24 is the value of RT_MANIFEST; we use it directly to avoid needing to share winapi.h with the tests and examples +1 24 "example.manifest" diff --git a/test/GNUfiles.mk b/test/GNUfiles.mk index 6b6feffe..4de5e9b7 100644 --- a/test/GNUfiles.mk +++ b/test/GNUfiles.mk @@ -15,7 +15,13 @@ CFILES += \ test/page7b.c \ test/page7c.c \ test/page8.c \ + test/page9.c \ test/spaced.c HFILES += \ test/test.h + +ifeq ($(OS),windows) +RCFILES += \ + test/resources.rc +endif diff --git a/test/main.c b/test/main.c index 7e41189e..675d1f4c 100644 --- a/test/main.c +++ b/test/main.c @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) int i; const char *err; uiWindow *w; - uiBox *page2, *page3, *page4, *page5, *page6, *page7, *page8; + uiBox *page2, *page3, *page4, *page5, *page6, *page7, *page8, *page9; uiTab *outerTab; uiTab *innerTab; int nomenus = 0; @@ -113,7 +113,7 @@ int main(int argc, char *argv[]) uiTabAppend(mainTab, "Page 5", uiControl(page5)); innerTab = newTab(); - uiTabAppend(outerTab, "Pages 6-8", uiControl(innerTab)); + uiTabAppend(outerTab, "Pages 6-9", uiControl(innerTab)); page6 = makePage6(); uiTabAppend(innerTab, "Page 6", uiControl(page6)); @@ -124,6 +124,9 @@ int main(int argc, char *argv[]) page8 = makePage8(); uiTabAppend(innerTab, "Page 8", uiControl(page8)); + page9 = makePage9(); + uiTabAppend(innerTab, "Page 9", uiControl(page9)); + if (startspaced) setSpaced(1); diff --git a/test/page7b.c b/test/page7b.c index 420155c8..d1f98a74 100644 --- a/test/page7b.c +++ b/test/page7b.c @@ -27,6 +27,7 @@ static void handlerMouseEvent(uiAreaHandler *a, uiArea *area, uiAreaMouseEvent * static void handlerMouseCrossed(uiAreaHandler *ah, uiArea *a, int left) { +printf("%d %d\n", left, !left); uiCheckboxSetChecked(label, !left); } diff --git a/test/page8.c b/test/page8.c new file mode 100644 index 00000000..3819257d --- /dev/null +++ b/test/page8.c @@ -0,0 +1,46 @@ +// 22 december 2015 +#include "test.h" + +static void onListFonts(uiButton *b, void *data) +{ + uiDrawFontFamilies *ff; + char *this; + uintmax_t i, n; + + uiMultilineEntrySetText(uiMultilineEntry(data), ""); + ff = uiDrawListFontFamilies(); + n = uiDrawFontFamiliesNumFamilies(ff); + for (i = 0; i < n; i++) { + this = uiDrawFontFamiliesFamily(ff, i); + uiMultilineEntryAppend(uiMultilineEntry(data), this); + uiMultilineEntryAppend(uiMultilineEntry(data), "\n"); + uiFreeText(this); + } + uiDrawFreeFontFamilies(ff); +} + +uiBox *makePage8(void) +{ + uiBox *page8; + uiGroup *group; + uiBox *vbox; + uiMultilineEntry *me; + uiButton *button; + + page8 = newHorizontalBox(); + + group = newGroup("Font Families"); + uiBoxAppend(page8, uiControl(group), 1); + + vbox = newVerticalBox(); + uiGroupSetChild(group, uiControl(vbox)); + + me = uiNewMultilineEntry(); + uiBoxAppend(vbox, uiControl(me), 1); + + button = uiNewButton("List Font Families"); + uiButtonOnClicked(button, onListFonts, me); + uiBoxAppend(vbox, uiControl(button), 0); + + return page8; +} diff --git a/test/page9.c b/test/page9.c new file mode 100644 index 00000000..a073788d --- /dev/null +++ b/test/page9.c @@ -0,0 +1,214 @@ +// 22 december 2015 +#include "test.h" + +static uiEntry *textString; +static uiEntry *textFont; +static uiEntry *textSize; +static uiCombobox *textWeight; +static uiCombobox *textItalic; +static uiCheckbox *textSmallCaps; +static uiCombobox *textStretch; +static uiEntry *textR, *textG, *textB, *textA; +static uiCheckbox *textHasBackground; +static uiEntry *textBR, *textBG, *textBB, *textBA; +static uiCheckbox *textHasStrikethrough; +static uiEntry *textSR, *textSG, *textSB, *textSA; +static uiCheckbox *textHasUnderline; +static uiEntry *textUR, *textUG, *textUB, *textUA; +static uiButton *textApply; +static uiArea *textArea; +static uiAreaHandler textAreaHandler; + +static double entryDouble(uiEntry *e) +{ + char *s; + double d; + + s = uiEntryText(e); + d = atof(s); + uiFreeText(s); + return d; +} + +static void handlerDraw(uiAreaHandler *a, uiArea *area, uiAreaDrawParams *dp) +{ + uiDrawTextStyle style; + char *s; + char *family; // make compiler happy + + memset(&style, 0, sizeof (uiDrawTextStyle)); + family = uiEntryText(textFont); + style.Family = family; + style.Size = entryDouble(textSize); + style.Weight = uiComboboxSelected(textWeight); + style.Italic = uiComboboxSelected(textItalic); + style.SmallCaps = uiCheckboxChecked(textSmallCaps); + style.Stretch = uiComboboxSelected(textStretch); + style.TextR = entryDouble(textR); + style.TextG = entryDouble(textG); + style.TextB = entryDouble(textB); + style.TextA = entryDouble(textA); + style.HasBackground = uiCheckboxChecked(textHasBackground); + style.BackgroundR = entryDouble(textBR); + style.BackgroundG = entryDouble(textBG); + style.BackgroundB = entryDouble(textBB); + style.BackgroundA = entryDouble(textBA); + style.HasStrikethrough = uiCheckboxChecked(textHasStrikethrough); + style.StrikethroughR = entryDouble(textSR); + style.StrikethroughG = entryDouble(textSG); + style.StrikethroughB = entryDouble(textSB); + style.StrikethroughA = entryDouble(textSA); + style.HasUnderline = uiCheckboxChecked(textHasUnderline); + style.UnderlineR = entryDouble(textUR); + style.UnderlineG = entryDouble(textUG); + style.UnderlineB = entryDouble(textUB); + style.UnderlineA = entryDouble(textUA); + s = uiEntryText(textString); + uiDrawText(dp->Context, 10, 10, s, &style); + uiFreeText(s); + uiFreeText(family); +} + +static void handlerMouseEvent(uiAreaHandler *a, uiArea *area, uiAreaMouseEvent *e) +{ + // do nothing +} + +static void handlerMouseCrossed(uiAreaHandler *ah, uiArea *a, int left) +{ + // do nothing +} + +static void handlerDragBroken(uiAreaHandler *ah, uiArea *a) +{ + // do nothing +} + +static int handlerKeyEvent(uiAreaHandler *ah, uiArea *a, uiAreaKeyEvent *e) +{ + // do nothing + return 0; +} + +static void onTextApply(uiButton *b, void *data) +{ + uiAreaQueueRedrawAll(textArea); +} + +static void mkRGBA(uiBox *parent, uiCheckbox **has, const char *hasText, uiEntry **r, uiEntry **g, uiEntry **b, uiEntry **a, const char *field) +{ + uiBox *hbox; + + hbox = newHorizontalBox(); + uiBoxAppend(parent, uiControl(hbox), 0); + + if (has != NULL) { + *has = uiNewCheckbox(hasText); + uiBoxAppend(hbox, uiControl(*has), 0); + } + + *r = uiNewEntry(); + uiEntrySetText(*r, field); + uiBoxAppend(hbox, uiControl(*r), 1); + + *g = uiNewEntry(); + uiEntrySetText(*g, field); + uiBoxAppend(hbox, uiControl(*g), 1); + + *b = uiNewEntry(); + uiEntrySetText(*b, field); + uiBoxAppend(hbox, uiControl(*b), 1); + + *a = uiNewEntry(); + uiEntrySetText(*a, "1.0"); + uiBoxAppend(hbox, uiControl(*a), 1); +} + +uiBox *makePage9(void) +{ + uiBox *page9; + uiBox *vbox; + uiBox *hbox; + + page9 = newVerticalBox(); + vbox = page9; + + hbox = newHorizontalBox(); + uiBoxAppend(vbox, uiControl(hbox), 0); + + textString = uiNewEntry(); + // TODO make it placeholder + uiEntrySetText(textString, "Enter text here"); + uiBoxAppend(hbox, uiControl(textString), 1); + + textFont = uiNewEntry(); + uiEntrySetText(textFont, "Arial"); + uiBoxAppend(hbox, uiControl(textFont), 1); + + textSize = uiNewEntry(); + uiEntrySetText(textSize, "10"); + uiBoxAppend(hbox, uiControl(textSize), 1); + + hbox = newHorizontalBox(); + uiBoxAppend(vbox, uiControl(hbox), 0); + + textWeight = uiNewCombobox(); + uiComboboxAppend(textWeight, "Thin"); + uiComboboxAppend(textWeight, "Ultra Light"); + uiComboboxAppend(textWeight, "Light"); + uiComboboxAppend(textWeight, "Book"); + uiComboboxAppend(textWeight, "Normal"); + uiComboboxAppend(textWeight, "Medium"); + uiComboboxAppend(textWeight, "Semi Bold"); + uiComboboxAppend(textWeight, "Bold"); + uiComboboxAppend(textWeight, "Utra Bold"); + uiComboboxAppend(textWeight, "Heavy"); + uiComboboxAppend(textWeight, "Ultra Heavy"); + uiComboboxSetSelected(textWeight, uiDrawTextWeightNormal); + uiBoxAppend(hbox, uiControl(textWeight), 1); + + textItalic = uiNewCombobox(); + uiComboboxAppend(textItalic, "Normal"); + uiComboboxAppend(textItalic, "Oblique"); + uiComboboxAppend(textItalic, "Italic"); + uiComboboxSetSelected(textItalic, uiDrawTextItalicNormal); + uiBoxAppend(hbox, uiControl(textItalic), 1); + + textSmallCaps = uiNewCheckbox("Small Caps"); + uiBoxAppend(hbox, uiControl(textSmallCaps), 1); + + hbox = newHorizontalBox(); + uiBoxAppend(vbox, uiControl(hbox), 0); + + textStretch = uiNewCombobox(); + uiComboboxAppend(textStretch, "Ultra Condensed"); + uiComboboxAppend(textStretch, "Extra Condensed"); + uiComboboxAppend(textStretch, "Condensed"); + uiComboboxAppend(textStretch, "Semi Condensed"); + uiComboboxAppend(textStretch, "Normal"); + uiComboboxAppend(textStretch, "Semi Expanded"); + uiComboboxAppend(textStretch, "Expanded"); + uiComboboxAppend(textStretch, "Extra Expanded"); + uiComboboxAppend(textStretch, "Ultra Expanded"); + uiComboboxSetSelected(textStretch, uiDrawTextStretchNormal); + uiBoxAppend(hbox, uiControl(textStretch), 1); + + mkRGBA(vbox, NULL, NULL, &textR, &textG, &textB, &textA, "0.0"); + mkRGBA(vbox, &textHasBackground, "Background", &textBR, &textBG, &textBB, &textBA, "1.0"); + mkRGBA(vbox, &textHasStrikethrough, "Strikethrough", &textSR, &textSG, &textSB, &textSA, "0.0"); + mkRGBA(vbox, &textHasUnderline, "Underline", &textUR, &textUG, &textUB, &textUA, "0.0"); + + textApply = uiNewButton("Apply"); + uiButtonOnClicked(textApply, onTextApply, NULL); + uiBoxAppend(vbox, uiControl(textApply), 0); + + textAreaHandler.Draw = handlerDraw; + textAreaHandler.MouseEvent = handlerMouseEvent; + textAreaHandler.MouseCrossed = handlerMouseCrossed; + textAreaHandler.DragBroken = handlerDragBroken; + textAreaHandler.KeyEvent = handlerKeyEvent; + textArea = uiNewArea(&textAreaHandler); + uiBoxAppend(vbox, uiControl(textArea), 1); + + return page9; +} diff --git a/test/resources.rc b/test/resources.rc new file mode 100644 index 00000000..11c78a76 --- /dev/null +++ b/test/resources.rc @@ -0,0 +1,9 @@ +// 30 may 2015 + +// this is a UTF-8 file +#pragma code_page(65001) + +// this is the Common Controls 6 manifest +// TODO set up the string values here +// 1 is the value of CREATEPROCESS_MANIFEST_RESOURCE_ID and 24 is the value of RT_MANIFEST; we use it directly to avoid needing to share winapi.h with the tests and examples +1 24 "test.manifest" diff --git a/test/test.h b/test/test.h index c277c62b..2d47c2b8 100644 --- a/test/test.h +++ b/test/test.h @@ -68,3 +68,6 @@ extern uiGroup *makePage7c(void); // page8.c extern uiBox *makePage8(void); + +// page9.c +extern uiBox *makePage9(void); diff --git a/test/test.manifest b/test/test.manifest new file mode 100644 index 00000000..41e7c9c5 --- /dev/null +++ b/test/test.manifest @@ -0,0 +1,20 @@ + + + +Your application description here. + + + + + + + + + + + diff --git a/ui.h b/ui.h index 2227389c..e4463119 100644 --- a/ui.h +++ b/ui.h @@ -460,6 +460,77 @@ _UI_EXTERN uintmax_t uiDrawFontFamiliesNumFamilies(uiDrawFontFamilies *ff); _UI_EXTERN char *uiDrawFontFamiliesFamily(uiDrawFontFamilies *ff, uintmax_t n); _UI_EXTERN void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff); +typedef struct uiDrawTextStyle uiDrawTextStyle; + +typedef enum uiDrawTextWeight { + uiDrawTextWeightThin, + uiDrawTextWeightUltraLight, + uiDrawTextWeightLight, + uiDrawTextWeightBook, + uiDrawTextWeightNormal, + uiDrawTextWeightMedium, + uiDrawTextWeightSemiBold, + uiDrawTextWeightBold, + uiDrawTextWeightUtraBold, + uiDrawTextWeightHeavy, + uiDrawTextWeightUltraHeavy, +} uiDrawTextWeight; + +// TODO drop Oblique? +typedef enum uiDrawTextItalic { + uiDrawTextItalicNormal, + uiDrawTextItalicOblique, + uiDrawTextItalicItalic, +} uiDrawTextItalic; + +typedef enum uiDrawTextStretch { + uiDrawTextStretchUltraCondensed, + uiDrawTextStretchExtraCondensed, + uiDrawTextStretchCondensed, + uiDrawTextStretchSemiCondensed, + uiDrawTextStretchNormal, + uiDrawTextStretchSemiExpanded, + uiDrawTextStretchExpanded, + uiDrawTextStretchExtraExpanded, + uiDrawTextStretchUltraExpanded, +} uiDrawTextStretch; + +struct uiDrawTextStyle { + const char *Family; + double Size; + uiDrawTextWeight Weight; + uiDrawTextItalic Italic; + int SmallCaps; + uiDrawTextStretch Stretch; + double TextR; + double TextG; + double TextB; + double TextA; + int HasBackground; + double BackgroundR; + double BackgroundG; + double BackgroundB; + double BackgroundA; // TODO Pango + int HasStrikethrough; + double StrikethroughR; + double StrikethroughG; + double StrikethroughB; + double StrikethroughA; // TODO Pango + int HasUnderline; + double UnderlineR; + double UnderlineG; + double UnderlineB; + double UnderlineA; // TODO Pango + const char *Language; // RFC 3066; NULL for default + // TODO other Pango attributes +}; + +_UI_EXTERN double uiDrawTextSizeToPoints(double textSize); +_UI_EXTERN double uiDrawPointsToTextSize(double points); + +// TODO make this more robust. +_UI_EXTERN void uiDrawText(uiDrawContext *c, double x, double y, const char *text, uiDrawTextStyle *style); + typedef enum uiModifiers { uiModifierCtrl = 1 << 0, uiModifierAlt = 1 << 1, diff --git a/unix/draw.c b/unix/draw.c index 83827694..006431b0 100644 --- a/unix/draw.c +++ b/unix/draw.c @@ -482,3 +482,94 @@ void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff) g_free(ff->f); uiFree(ff); } + +double uiDrawTextSizeToPoints(double textSize) +{ + gint pangoSize; + + pangoSize = (gint) (textSize * PANGO_SCALE); + return ((double) pangoSize) / PANGO_SCALE; +} + +double uiDrawPointsToTextSize(double points) +{ + // yeah, as far as I can tell the two functions are equivalent + // TODO verify + // TODO make sure they aren't just equivalent + return uiDrawTextSizeToPoints(points); +} + +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, + [uiDrawTextWeightUtraBold] = PANGO_WEIGHT_ULTRABOLD, + [uiDrawTextWeightHeavy] = PANGO_WEIGHT_HEAVY, + [uiDrawTextWeightUltraHeavy] = PANGO_WEIGHT_ULTRAHEAVY, +}; + +static const PangoStyle pangoItalics[] = { + [uiDrawTextItalicNormal] = PANGO_STYLE_NORMAL, + [uiDrawTextItalicOblique] = PANGO_STYLE_OBLIQUE, + [uiDrawTextItalicItalic] = PANGO_STYLE_ITALIC, +}; + +static const PangoStretch pangoStretches[] = { + [uiDrawTextStretchUltraCondensed] = PANGO_STRETCH_ULTRA_CONDENSED, + [uiDrawTextStretchExtraCondensed] = PANGO_STRETCH_EXTRA_CONDENSED, + [uiDrawTextStretchCondensed] = PANGO_STRETCH_CONDENSED, + [uiDrawTextStretchSemiCondensed] = PANGO_STRETCH_SEMI_CONDENSED, + [uiDrawTextStretchNormal] = PANGO_STRETCH_NORMAL, + [uiDrawTextStretchSemiExpanded] = PANGO_STRETCH_SEMI_EXPANDED, + [uiDrawTextStretchExpanded] = PANGO_STRETCH_EXPANDED, + [uiDrawTextStretchExtraExpanded] = PANGO_STRETCH_EXTRA_EXPANDED, + [uiDrawTextStretchUltraExpanded] = PANGO_STRETCH_ULTRA_EXPANDED, +}; + +void uiDrawText(uiDrawContext *c, double x, double y, const char *text, uiDrawTextStyle *style) +{ + PangoAttrList *attrs; + PangoLayout *layout; + + attrs = pango_attr_list_new(); + pango_attr_list_insert(attrs, + pango_attr_family_new(style->Family)); + pango_attr_list_insert(attrs, + pango_attr_size_new((gint) (style->Size * PANGO_SCALE))); + pango_attr_list_insert(attrs, + pango_attr_weight_new(pangoWeights[style->Weight])); + pango_attr_list_insert(attrs, + pango_attr_style_new(pangoItalics[style->Italic])); + if (style->SmallCaps) + pango_attr_list_insert(attrs, + pango_attr_variant_new(PANGO_VARIANT_SMALL_CAPS)); + pango_attr_list_insert(attrs, + pango_attr_stretch_new(pangoStretches[style->Stretch])); + cairo_set_source_rgba(c->cr, style->TextR, style->TextG, style->TextB, style->TextA); + if (style->HasBackground) { + // TODO + } + if (style->HasStrikethrough) { + // TODO + } + if (style->HasUnderline) { + // TODO + } + if (style->Language != NULL) + pango_attr_list_insert(attrs, + pango_attr_language_new(pango_language_from_string(style->Language))); + + layout = pango_cairo_create_layout(c->cr); + pango_layout_set_text(layout, text, -1); + pango_layout_set_attributes(layout, attrs); + cairo_move_to(c->cr, x, y); + pango_cairo_show_layout(c->cr, layout); + + g_object_unref(layout); + pango_attr_list_unref(attrs); +} diff --git a/windows/drawtext.cpp b/windows/drawtext.cpp index a644ca38..a3b01edd 100644 --- a/windows/drawtext.cpp +++ b/windows/drawtext.cpp @@ -107,3 +107,20 @@ void uiDrawFreeFontFamilies(uiDrawFontFamilies *ff) ff->fonts->Release(); uiFree(ff); } + +double uiDrawTextSizeToPoints(double textSize) +{ + // TODO + return 0; +} + +double uiDrawPointsToTextSize(double points) +{ + // TODO + return 0; +} + +void uiDrawText(uiDrawContext *c, double x, double y, const char *text, uiDrawTextStyle *style) +{ + // TODO +} diff --git a/windows/libui.manifest b/windows/libui.manifest index 903c5359..8beb6cfc 100644 --- a/windows/libui.manifest +++ b/windows/libui.manifest @@ -19,5 +19,13 @@ /> + + + + + + + +