From 246950deed73be2c2c6175496b1e72b96f8f4d46 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 26 Aug 2018 17:17:03 -0400 Subject: Migrated drawtext.go and fontbutton.go. --- BBB_GOFILES/drawtext.go | 554 ---------------------------------------------- BBB_GOFILES/fontbutton.go | 69 ------ colorbutton.go | 2 +- drawtext.go | 512 ++++++++++++++++++++++++++++++++++++++++++ fontbutton.go | 56 +++++ pkgui.c | 43 +++- pkgui.h | 11 + 7 files changed, 615 insertions(+), 632 deletions(-) delete mode 100644 BBB_GOFILES/drawtext.go delete mode 100644 BBB_GOFILES/fontbutton.go create mode 100644 drawtext.go create mode 100644 fontbutton.go diff --git a/BBB_GOFILES/drawtext.go b/BBB_GOFILES/drawtext.go deleted file mode 100644 index 1cd438c..0000000 --- a/BBB_GOFILES/drawtext.go +++ /dev/null @@ -1,554 +0,0 @@ -// 12 august 2018 - -package ui - -// #include -// #include "ui.h" -// #include "util.h" -// typedef struct pkguiCColor pkguiCColor; -// struct pkguiCColor { double *r; double *g; double *b; double *a; }; -// static inline pkguiCColor pkguiNewCColor(void) -// { -// pkguiCColor c; -// -// c.r = (double *) pkguiAlloc(4 * sizeof (double)); -// c.g = c.r + 1; -// c.b = c.g + 1; -// c.a = c.b + 1; -// return c; -// } -// static inline void pkguiFreeCColor(pkguiCColor c) -// { -// free(c.r); -// } -// static inline uiUnderlineColor *pkguiNewUnderlineColor(void) -// { -// return (uiUnderlineColor *) pkguiAlloc(sizeof (uiUnderlineColor)); -// } -// static inline void pkguiFreeUnderlineColor(uiUnderlineColor *c) -// { -// free(c); -// } -// static inline uiFontDescriptor *pkguiNewFontDescriptor(void) -// { -// return (uiFontDescriptor *) pkguiAlloc(sizeof (uiFontDescriptor)); -// } -// static inline void pkguiFreeFontDescriptor(uiFontDescriptor *fd) -// { -// free(fd); -// } -// static inline uiDrawTextLayoutParams *pkguiNewDrawTextLayoutParams(void) -// { -// return (uiDrawTextLayoutParams *) pkguiAlloc(sizeof (uiDrawTextLayoutParams)); -// } -// static inline void pkguiFreeDrawTextLayoutParams(uiDrawTextLayoutParams *fd) -// { -// free(fd); -// } -import "C" - -// Attribute stores information about an attribute in an -// AttributedString. -// -// The following types can be used as Attributes: -// -// - TextFamily -// - TextSize -// - TextWeight -// - TextItalic -// - TextStretch -// - TextColor -// - TextBackground -// - Underline -// - UnderlineColor -// - UnderlineColorCustom -// - OpenTypeFeatures -// -// For every Unicode codepoint in the AttributedString, at most one -// value of each attribute type can be applied. -type Attribute interface { - toLibui() *C.uiAttribute -} - -// TextFamily is an Attribute that changes the font family of the text -// it is applied to. Font family names are case-insensitive. -type TextFamily string - -func (f TextFamily) toLibui() *C.uiAttribute { - fstr := C.CString(string(f)) - defer freestr(fstr) - return C.uiNewFamilyAttribute(fstr) -} - -// TextSize is an Attribute that changes the size of the text it is -// applied to, in typographical points. -type TextSize float64 - -func (s TextSize) toLibui() *C.uiAttribute { - return C.uiNewSizeAttribute(C.double(s)) -} - -// TextWeight is an Attribute that changes the weight of the text -// it is applied to. These roughly map to the OS/2 text weight field -// of TrueType and OpenType fonts, or to CSS weight numbers. The -// named constants are nominal values; the actual values may vary -// by font and by OS, though this isn't particularly likely. Any value -// between TextWeightMinimum and TextWeightMaximum, -// inclusive, is allowed. -// -// Note that due to restrictions in early versions of Windows, some -// fonts have "special" weights be exposed in many programs as -// separate font families. This is perhaps most notable with -// Arial Black. Package ui does not do this, even on Windows -// (because the DirectWrite API libui uses on Windows does not do -// this); to specify Arial Black, use family Arial and weight -// TextWeightBlack. -type TextWeight int -const ( - TextWeightMinimum TextWeight = 0 - TextWeightThin TextWeight = 100 - TextWeightUltraLight TextWeight = 200 - TextWeightLight TextWeight = 300 - TextWeightBook TextWeight = 350 - TextWeightNormal TextWeight = 400 - TextWeightMedium TextWeight = 500 - TextWeightSemiBold TextWeight = 600 - TextWeightBold TextWeight = 700 - TextWeightUltraBold TextWeight = 800 - TextWeightHeavy TextWeight = 900 - TextWeightUltraHeavy TextWeight = 950 - TextWeightMaximum TextWeight = 1000 -) - -func (w TextWeight) toLibui() *C.uiAttribute { - return C.uiNewWeightAttribute(C.uiTextWeight(w)) -} - -// TextItalic is an Attribute that changes the italic mode of the text -// it is applied to. Italic represents "true" italics where the slanted -// glyphs have custom shapes, whereas oblique represents italics -// that are merely slanted versions of the normal glyphs. Most fonts -// usually have one or the other. -type TextItalic int -const ( - TextItalicNormal TextItalic = iota - TextItalicOblique - TextItalicItalic -) - -func (i TextItalic) toLibui() *C.uiAttribute { - return C.uiNewItalicAttribute(C.uiTextItalic(i)) -} - -// TextStretch is an Attribute that changes the stretch (also called -// "width") of the text it is applied to. -// -// Note that due to restrictions in early versions of Windows, some -// fonts have "special" stretches be exposed in many programs as -// separate font families. This is perhaps most notable with -// Arial Condensed. Package ui does not do this, even on Windows -// (because the DirectWrite API package ui uses on Windows does -// not do this); to specify Arial Condensed, use family Arial and -// stretch TextStretchCondensed. -type TextStretch int -const ( - TextStretchUltraCondensed TextStretch = iota - TextStretchExtraCondensed - TextStretchCondensed - TextStretchSemiCondensed - TextStretchNormal - TextStretchSemiExpanded - TextStretchExpanded - TextStretchExtraExpanded - TextStretchUltraExpanded -) - -func (s TextStretch) toLibui() *C.uiAttribute { - return C.uiNewStretchAttribute(C.uiTextStretch(s)) -} - -// TextColor is an Attribute that changes the color of the text it is -// applied to. -type TextColor struct { - R float64 - G float64 - B float64 - A float64 -} - -func (c TextColor) toLibui() *C.uiAttribute { - return C.uiNewColorAttribute(C.double(c.R), C.double(c.G), C.double(c.B), C.double(c.A)) -} - -// TextBackground is an Attribute that changes the background -// color of the text it is applied to. -type TextBackground struct { - R float64 - G float64 - B float64 - A float64 -} - -func (b TextBackground) toLibui() *C.uiAttribute { - return C.uiNewBackgroundAttribute(C.double(b.R), C.double(b.G), C.double(b.B), C.double(b.A)) -} - -// Underline is an Attribute that specifies a type of underline to use -// on text. -type Underline int -const ( - UnderlineNone Underline = iota - UnderlineSingle - UnderlineDouble - UnderlineSuggestion // wavy or dotted underlines used for spelling/grammar checkers -) - -func (u Underline) toLibui() *C.uiAttribute { - return C.uiNewUnderlineAttribute(C.uiUnderline(u)) -} - -// UnderlineColor is an Attribute that changes the color of any -// underline on the text it is applied to, regardless of the type of -// underline. In addition to being able to specify the -// platform-specific colors for suggestion underlines here, you can -// also use a custom color with UnderlineColorCustom. -// -// To use the constants here correctly, pair them with -// UnderlineSuggestion (though they can be used on other types of -// underline as well). -// -// If an underline type is applied but no underline color is -// specified, the text color is used instead. If an underline color -// is specified without an underline type, the underline color -// attribute is ignored, but not removed from the uiAttributedString. -type UnderlineColor int -const ( - UnderlineColorSpelling UnderlineColor = iota + 1 - UnderlineColorGrammar - UnderlineColorAuxiliary // for instance, the color used by smart replacements on macOS or in Microsoft Office -) - -func (u UnderlineColor) toLibui() *C.uiAttribute { - return C.uiNewUnderlineColorAttribute(C.uiUnderlineColor(u), 0, 0, 0, 0) -} - -// UnderlineColorCustom is an Attribute like UnderlineColor, except -// it allows specifying a custom color. -type UnderlineColorCustom struct { - R float64 - G float64 - B float64 - A float64 -} - -func (u UnderlineColorCustom) toLibui() *C.uiAttribute { - return C.uiNewUnderlineColorAttribute(C.uiUnderlineColorCustom, C.double(u.R), C.double(u.G), C.double(u.B), C.double(u.A)) -} - -// OpenTypeFeatures is an Attribute that represents a set of -// OpenType feature tag-value pairs, for applying OpenType -// features to text. OpenType feature tags are four-character codes -// defined by OpenType that cover things from design features like -// small caps and swashes to language-specific glyph shapes and -// beyond. Each tag may only appear once in any given -// uiOpenTypeFeatures instance. Each value is a 32-bit integer, -// often used as a Boolean flag, but sometimes as an index to choose -// a glyph shape to use. -// -// If a font does not support a certain feature, that feature will be -// ignored. (TODO verify this on all OSs) -// -// See the OpenType specification at -// https://www.microsoft.com/typography/otspec/featuretags.htm -// for the complete list of available features, information on specific -// features, and how to use them. -// TODO invalid features -// -// Note that if a feature is not present in a OpenTypeFeatures, -// the feature is NOT treated as if its value was zero, unlike in Go. -// Script-specific font shaping rules and font-specific feature -// settings may use a different default value for a feature. You -// should likewise NOT treat a missing feature as having a value of -// zero either. Instead, a missing feature should be treated as -// having some unspecified default value. -// -// Note that despite OpenTypeFeatures being a map, its contents -// are copied by AttributedString. Modifying an OpenTypeFeatures -// after giving it to an AttributedString, or modifying one that comes -// out of an AttributedString, will have no effect. -type OpenTypeFeatures map[OpenTypeTag]uint32 - -func (o OpenTypeFeatures) toLibui() *C.uiAttribute { - otf := C.uiNewOpenTypeFeatures() - defer C.uiFreeOpenTypeFeatures(otf) - for tag, value := range o { - a := byte((tag >> 24) & 0xFF) - b := byte((tag >> 16) & 0xFF) - c := byte((tag >> 8) & 0xFF) - d := byte(tag & 0xFF) - C.uiOpenTypeFeaturesAdd(otf, C.char(a), C.char(b), C.char(c), C.char(d), C.uint32_t(value)) - } - return C.uiNewFeaturesAttribute(otf) -} - -// OpenTypeTag represents a four-byte OpenType feature tag. -type OpenTypeTag uint32 - -// ToOpenTypeTag converts the four characters a, b, c, and d into -// an OpenTypeTag. -func ToOpenTypeTag(a, b, c, d byte) OpenTypeTag { - return (OpenTypeTag(a) << 24) | - (OpenTypeTag(b) << 16) | - (OpenTypeTag(c) << 8) | - OpenTypeTag(d) -} - -func attributeFromLibui(a *C.uiAttribute) Attribute { - switch C.uiAttributeGetType(a) { - case C.uiAttributeTypeFamily: - cf := C.uiAttributeFamily(a) - return TextFamily(C.GoString(cf)) - case C.uiAttributeTypeSize: - return TextSize(C.uiAttributeSize(a)) - case C.uiAttributeTypeWeight: - return TextWeight(C.uiAttributeWeight(a)) - case C.uiAttributeTypeItalic: - return TextItalic(C.uiAttributeItalic(a)) - case C.uiAttributeTypeStretch: - return TextStretch(C.uiAttributeStretch(a)) - case C.uiAttributeTypeColor: - cc := C.pkguiNewCColor() - defer C.pkguiFreeCColor(cc) - C.uiAttributeColor(a, cc.r, cc.g, cc.b, cc.a) - return TextColor{ - R: float64(*(cc.r)), - G: float64(*(cc.g)), - B: float64(*(cc.b)), - A: float64(*(cc.a)), - } - case C.uiAttributeTypeBackground: - cc := C.pkguiNewCColor() - defer C.pkguiFreeCColor(cc) - C.uiAttributeColor(a, cc.r, cc.g, cc.b, cc.a) - return TextBackground{ - R: float64(*(cc.r)), - G: float64(*(cc.g)), - B: float64(*(cc.b)), - A: float64(*(cc.a)), - } - case C.uiAttributeTypeUnderline: - return Underline(C.uiAttributeUnderline(a)) - case C.uiAttributeTypeUnderlineColor: - cu := C.pkguiNewUnderlineColor() - defer C.pkguiFreeUnderlineColor(cu) - cc := C.pkguiNewCColor() - defer C.pkguiFreeCColor(cc) - C.uiAttributeUnderlineColor(a, cu, cc.r, cc.g, cc.b, cc.a) - if *cu == C.uiUnderlineColorCustom { - return UnderlineColorCustom{ - R: float64(*(cc.r)), - G: float64(*(cc.g)), - B: float64(*(cc.b)), - A: float64(*(cc.a)), - } - } - return UnderlineColor(*cu) - case C.uiAttributeTypeFeatures: - // TODO - } - panic("unreachable") -} - -// AttributedString represents a string of UTF-8 text that can -// optionally be embellished with formatting attributes. Package ui -// provides the list of formatting attributes, which cover common -// formatting traits like boldface and color as well as advanced -// typographical features provided by OpenType like superscripts -// and small caps. These attributes can be combined in a variety of -// ways. -// -// Attributes are applied to runs of Unicode codepoints in the string. -// Zero-length runs are elided. Consecutive runs that have the same -// attribute type and value are merged. Each attribute is independent -// of each other attribute; overlapping attributes of different types -// do not split each other apart, but different values of the same -// attribute type do. -// -// The empty string can also be represented by AttributedString, -// but because of the no-zero-length-attribute rule, it will not have -// attributes. -// -// Unlike Go strings, AttributedStrings are mutable. -// -// AttributedString allocates resources within libui, which package -// ui sits on top of. As such, when you are finished with an -// AttributedString, you must free it with Free. Like other things in -// package ui, AttributedString must only be used from the main -// goroutine. -// -// In addition, AttributedString provides facilities for moving -// between grapheme clusters, which represent a character -// from the point of view of the end user. The cursor of a text editor -// is always placed on a grapheme boundary, so you can use these -// features to move the cursor left or right by one "character". -// TODO does uiAttributedString itself need this -// -// AttributedString does not provide enough information to be able -// to draw itself onto a DrawContext or respond to user actions. -// In order to do that, you'll need to use a DrawTextLayout, which -// is built from the combination of an AttributedString and a set of -// layout-specific properties. -type AttributedString struct { - s *C.uiAttributedString -} - -// NewAttributedString creates a new AttributedString from -// initialString. The string will be entirely unattributed. -func NewAttributedString(initialString string) *AttributedString { - cs := C.CString(initialString) - defer freestr(cs) - return &AttributedString{ - s: C.uiNewAttributedString(cs), - } -} - -// Free destroys s. -func (s *AttributedString) Free() { - C.uiFreeAttributedString(s.s) -} - -// String returns the textual content of s. -func (s *AttributedString) String() string { - return C.GoString(C.uiAttributedStringString(s.s)) -} - -// AppendUnattributed adds str to the end of s. The new substring -// will be unattributed. -func (s *AttributedString) AppendUnattributed(str string) { - cs := C.CString(str) - defer freestr(cs) - C.uiAttributedStringAppendUnattributed(s.s, cs) -} - -// InsertAtUnattributed adds str to s at the byte position specified by -// at. The new substring will be unattributed; existing attributes will -// be moved along with their text. -func (s *AttributedString) InsertAtUnattributed(str string, at int) { - cs := C.CString(str) - defer freestr(cs) - C.uiAttributedStringInsertAtUnattributed(s.s, cs, C.size_t(at)) -} - -// Delete deletes the characters and attributes of s in the byte range -// [start, end). -func (s *AttributedString) Delete(start, end int) { - C.uiAttributedStringDelete(s.s, C.size_t(start), C.size_t(end)) -} - -// SetAttribute sets a in the byte range [start, end) of s. Any existing -// attributes in that byte range of the same type are removed. -func (s *AttributedString) SetAttribute(a Attribute, start, end int) { - C.uiAttributedStringSetAttribute(s.s, a.toLibui(), C.size_t(start), C.size_t(end)) -} - -// TODO uiAttributedStringForEachAttribute -// TODO uiAttributedStringNumGraphemes -// TODO uiAttributedStringByteIndexToGrapheme -// TODO uiAttributedStringGraphemeToByteIndex - -// FontDescriptor provides a complete description of a font where -// one is needed. Currently, this means as the default font of a -// DrawTextLayout and as the data returned by FontButton. -type FontDescriptor struct { - Family TextFamily - Size TextSize - Weight TextWeight - Italic TextItalic - Stretch TextStretch -} - -func (d *FontDescriptor) fromLibui(fd *C.uiFontDescriptor) { - d.Family = TextFamily(C.GoString(fd.Family)) - d.Size = TextSize(fd.Size) - d.Weight = TextWeight(fd.Weight) - d.Italic = TextItalic(fd.Italic) - d.Stretch = TextStretch(fd.Stretch) -} - -func (d *FontDescriptor) toLibui() *C.uiFontDescriptor { - fd := C.pkguiNewFontDescriptor() - fd.Family = C.CString(string(d.Family)) - fd.Size = C.double(d.Size) - fd.Weight = C.uiTextWeight(d.Weight) - fd.Italic = C.uiTextItalic(d.Italic) - fd.Stretch = C.uiTextStretch(d.Stretch) - return fd -} - -func freeLibuiFontDescriptor(fd *C.uiFontDescriptor) { - freestr(fd.Family) - C.pkguiFreeFontDescriptor(fd) -} - -// DrawTextLayout is a concrete representation of an -// AttributedString that can be displayed in a DrawContext. -// It includes information important for the drawing of a block of -// text, including the bounding box to wrap the text within, the -// alignment of lines of text within that box, areas to mark as -// being selected, and other things. -// -// Unlike AttributedString, the content of a DrawTextLayout is -// immutable once it has been created. -// -// TODO talk about OS-specific differences with text drawing that libui can't account for... -type DrawTextLayout struct { - tl *C.uiDrawTextLayout -} - -// DrawTextAlign specifies the alignment of lines of text in a -// DrawTextLayout. -// TODO should this really have Draw in the name? -type DrawTextAlign int -const ( - DrawTextAlignLeft DrawTextAlign = iota - DrawTextAlignCenter - DrawTextAlignRight -) - -// DrawTextLayoutParams describes a DrawTextLayout. -// DefaultFont is used to render any text that is not attributed -// sufficiently in String. Width determines the width of the bounding -// box of the text; the height is determined automatically. -type DrawTextLayoutParams struct { - String *AttributedString - DefaultFont *FontDescriptor - Width float64 - Align DrawTextAlign -} - -// DrawNewTextLayout() creates a new DrawTextLayout from -// the given parameters. -func DrawNewTextLayout(p *DrawTextLayoutParams) *DrawTextLayout { - dp := C.pkguiNewDrawTextLayoutParams() - defer C.pkguiFreeDrawTextLayoutParams(dp) - dp.String = p.String.s - dp.DefaultFont = p.DefaultFont.toLibui() - defer freeLibuiFontDescriptor(dp.DefaultFont) - dp.Width = C.double(p.Width) - dp.Align = C.uiDrawTextAlign(p.Align) - return &DrawTextLayout{ - tl: C.uiDrawNewTextLayout(dp), - } -} - -// Free frees tl. The underlying AttributedString is not freed. -func (tl *DrawTextLayout) Free() { - C.uiDrawFreeTextLayout(tl.tl) -} - -// Text draws tl in c with the top-left point of tl at (x, y). -func (c *DrawContext) Text(tl *DrawTextLayout, x, y float64) { - C.uiDrawText(c.c, tl.tl, C.double(x), C.double(y)) -} - -// TODO uiDrawTextLayoutExtents diff --git a/BBB_GOFILES/fontbutton.go b/BBB_GOFILES/fontbutton.go deleted file mode 100644 index c228151..0000000 --- a/BBB_GOFILES/fontbutton.go +++ /dev/null @@ -1,69 +0,0 @@ -// 12 december 2015 - -package ui - -import ( - "unsafe" -) - -// #include -// #include "ui.h" -// #include "util.h" -// extern void doFontButtonOnChanged(uiFontButton *, void *); -// // see golang/go#19835 -// typedef void (*fontButtonCallback)(uiFontButton *, void *); -// static inline uiFontDescriptor *pkguiNewFontDescriptor(void) -// { -// return (uiFontDescriptor *) pkguiAlloc(sizeof (uiFontDescriptor)); -// } -// static inline void pkguiFreeFontDescriptor(uiFontDescriptor *fd) -// { -// free(fd); -// } -import "C" - -// FontButton is a Control that represents a button that the user can -// click to select a font. -type FontButton struct { - ControlBase - b *C.uiFontButton - onChanged func(*FontButton) -} - -// NewFontButton creates a new FontButton. -func NewFontButton() *FontButton { - b := new(FontButton) - - b.b = C.uiNewFontButton() - - C.uiFontButtonOnChanged(b.b, C.fontButtonCallback(C.doFontButtonOnChanged), nil) - - b.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b))) - return b -} - -// Font returns the font currently selected in the FontButton. -func (b *FontButton) Font() *FontDescriptor { - cfd := C.pkguiNewFontDescriptor() - defer C.pkguiFreeFontDescriptor(cfd) - C.uiFontButtonFont(b.b, cfd) - defer C.uiFreeFontButtonFont(cfd) - fd := &FontDescriptor{} - fd.fromLibui(cfd) - return fd -} - -// OnChanged registers f to be run when the user changes the -// currently selected font in the FontButton. Only one function can -// be registered at a time. -func (b *FontButton) OnChanged(f func(*FontButton)) { - b.onChanged = f -} - -//export doFontButtonOnChanged -func doFontButtonOnChanged(bb *C.uiFontButton, data unsafe.Pointer) { - b := ControlFromLibui(uintptr(unsafe.Pointer(bb))).(*FontButton) - if b.onChanged != nil { - b.onChanged(b) - } -} diff --git a/colorbutton.go b/colorbutton.go index 6b1f525..f10c5c8 100644 --- a/colorbutton.go +++ b/colorbutton.go @@ -33,7 +33,7 @@ func NewColorButton() *ColorButton { // Colors are not alpha-premultiplied. // TODO rename b or bl func (b *ColorButton) Color() (r, g, bl, a float64) { - c := C.pkguiNewColorDoubles() + c := C.pkguiAllocColorDoubles() defer C.pkguiFreeColorDoubles(c) C.uiColorButtonColor(b.b, c.r, c.g, c.b, c.a) return float64(*(c.r)), float64(*(c.g)), float64(*(c.b)), float64(*(c.a)) diff --git a/drawtext.go b/drawtext.go new file mode 100644 index 0000000..930416f --- /dev/null +++ b/drawtext.go @@ -0,0 +1,512 @@ +// 12 august 2018 + +package ui + +// #include "pkgui.h" +import "C" + +// Attribute stores information about an attribute in an +// AttributedString. +// +// The following types can be used as Attributes: +// +// - TextFamily +// - TextSize +// - TextWeight +// - TextItalic +// - TextStretch +// - TextColor +// - TextBackground +// - Underline +// - UnderlineColor +// - UnderlineColorCustom +// - OpenTypeFeatures +// +// For every Unicode codepoint in the AttributedString, at most one +// value of each attribute type can be applied. +type Attribute interface { + toLibui() *C.uiAttribute +} + +// TextFamily is an Attribute that changes the font family of the text +// it is applied to. Font family names are case-insensitive. +type TextFamily string + +func (f TextFamily) toLibui() *C.uiAttribute { + fstr := C.CString(string(f)) + defer freestr(fstr) + return C.uiNewFamilyAttribute(fstr) +} + +// TextSize is an Attribute that changes the size of the text it is +// applied to, in typographical points. +type TextSize float64 + +func (s TextSize) toLibui() *C.uiAttribute { + return C.uiNewSizeAttribute(C.double(s)) +} + +// TextWeight is an Attribute that changes the weight of the text +// it is applied to. These roughly map to the OS/2 text weight field +// of TrueType and OpenType fonts, or to CSS weight numbers. The +// named constants are nominal values; the actual values may vary +// by font and by OS, though this isn't particularly likely. Any value +// between TextWeightMinimum and TextWeightMaximum, +// inclusive, is allowed. +// +// Note that due to restrictions in early versions of Windows, some +// fonts have "special" weights be exposed in many programs as +// separate font families. This is perhaps most notable with +// Arial Black. Package ui does not do this, even on Windows +// (because the DirectWrite API libui uses on Windows does not do +// this); to specify Arial Black, use family Arial and weight +// TextWeightBlack. +type TextWeight int +const ( + TextWeightMinimum TextWeight = 0 + TextWeightThin TextWeight = 100 + TextWeightUltraLight TextWeight = 200 + TextWeightLight TextWeight = 300 + TextWeightBook TextWeight = 350 + TextWeightNormal TextWeight = 400 + TextWeightMedium TextWeight = 500 + TextWeightSemiBold TextWeight = 600 + TextWeightBold TextWeight = 700 + TextWeightUltraBold TextWeight = 800 + TextWeightHeavy TextWeight = 900 + TextWeightUltraHeavy TextWeight = 950 + TextWeightMaximum TextWeight = 1000 +) + +func (w TextWeight) toLibui() *C.uiAttribute { + return C.uiNewWeightAttribute(C.uiTextWeight(w)) +} + +// TextItalic is an Attribute that changes the italic mode of the text +// it is applied to. Italic represents "true" italics where the slanted +// glyphs have custom shapes, whereas oblique represents italics +// that are merely slanted versions of the normal glyphs. Most fonts +// usually have one or the other. +type TextItalic int +const ( + TextItalicNormal TextItalic = iota + TextItalicOblique + TextItalicItalic +) + +func (i TextItalic) toLibui() *C.uiAttribute { + return C.uiNewItalicAttribute(C.uiTextItalic(i)) +} + +// TextStretch is an Attribute that changes the stretch (also called +// "width") of the text it is applied to. +// +// Note that due to restrictions in early versions of Windows, some +// fonts have "special" stretches be exposed in many programs as +// separate font families. This is perhaps most notable with +// Arial Condensed. Package ui does not do this, even on Windows +// (because the DirectWrite API package ui uses on Windows does +// not do this); to specify Arial Condensed, use family Arial and +// stretch TextStretchCondensed. +type TextStretch int +const ( + TextStretchUltraCondensed TextStretch = iota + TextStretchExtraCondensed + TextStretchCondensed + TextStretchSemiCondensed + TextStretchNormal + TextStretchSemiExpanded + TextStretchExpanded + TextStretchExtraExpanded + TextStretchUltraExpanded +) + +func (s TextStretch) toLibui() *C.uiAttribute { + return C.uiNewStretchAttribute(C.uiTextStretch(s)) +} + +// TextColor is an Attribute that changes the color of the text it is +// applied to. +type TextColor struct { + R float64 + G float64 + B float64 + A float64 +} + +func (c TextColor) toLibui() *C.uiAttribute { + return C.uiNewColorAttribute(C.double(c.R), C.double(c.G), C.double(c.B), C.double(c.A)) +} + +// TextBackground is an Attribute that changes the background +// color of the text it is applied to. +type TextBackground struct { + R float64 + G float64 + B float64 + A float64 +} + +func (b TextBackground) toLibui() *C.uiAttribute { + return C.uiNewBackgroundAttribute(C.double(b.R), C.double(b.G), C.double(b.B), C.double(b.A)) +} + +// Underline is an Attribute that specifies a type of underline to use +// on text. +type Underline int +const ( + UnderlineNone Underline = iota + UnderlineSingle + UnderlineDouble + UnderlineSuggestion // wavy or dotted underlines used for spelling/grammar checkers +) + +func (u Underline) toLibui() *C.uiAttribute { + return C.uiNewUnderlineAttribute(C.uiUnderline(u)) +} + +// UnderlineColor is an Attribute that changes the color of any +// underline on the text it is applied to, regardless of the type of +// underline. In addition to being able to specify the +// platform-specific colors for suggestion underlines here, you can +// also use a custom color with UnderlineColorCustom. +// +// To use the constants here correctly, pair them with +// UnderlineSuggestion (though they can be used on other types of +// underline as well). +// +// If an underline type is applied but no underline color is +// specified, the text color is used instead. If an underline color +// is specified without an underline type, the underline color +// attribute is ignored, but not removed from the uiAttributedString. +type UnderlineColor int +const ( + UnderlineColorSpelling UnderlineColor = iota + 1 + UnderlineColorGrammar + UnderlineColorAuxiliary // for instance, the color used by smart replacements on macOS or in Microsoft Office +) + +func (u UnderlineColor) toLibui() *C.uiAttribute { + return C.uiNewUnderlineColorAttribute(C.uiUnderlineColor(u), 0, 0, 0, 0) +} + +// UnderlineColorCustom is an Attribute like UnderlineColor, except +// it allows specifying a custom color. +type UnderlineColorCustom struct { + R float64 + G float64 + B float64 + A float64 +} + +func (u UnderlineColorCustom) toLibui() *C.uiAttribute { + return C.uiNewUnderlineColorAttribute(C.uiUnderlineColorCustom, C.double(u.R), C.double(u.G), C.double(u.B), C.double(u.A)) +} + +// OpenTypeFeatures is an Attribute that represents a set of +// OpenType feature tag-value pairs, for applying OpenType +// features to text. OpenType feature tags are four-character codes +// defined by OpenType that cover things from design features like +// small caps and swashes to language-specific glyph shapes and +// beyond. Each tag may only appear once in any given +// uiOpenTypeFeatures instance. Each value is a 32-bit integer, +// often used as a Boolean flag, but sometimes as an index to choose +// a glyph shape to use. +// +// If a font does not support a certain feature, that feature will be +// ignored. (TODO verify this on all OSs) +// +// See the OpenType specification at +// https://www.microsoft.com/typography/otspec/featuretags.htm +// for the complete list of available features, information on specific +// features, and how to use them. +// TODO invalid features +// +// Note that if a feature is not present in a OpenTypeFeatures, +// the feature is NOT treated as if its value was zero, unlike in Go. +// Script-specific font shaping rules and font-specific feature +// settings may use a different default value for a feature. You +// should likewise NOT treat a missing feature as having a value of +// zero either. Instead, a missing feature should be treated as +// having some unspecified default value. +// +// Note that despite OpenTypeFeatures being a map, its contents +// are copied by AttributedString. Modifying an OpenTypeFeatures +// after giving it to an AttributedString, or modifying one that comes +// out of an AttributedString, will have no effect. +type OpenTypeFeatures map[OpenTypeTag]uint32 + +func (o OpenTypeFeatures) toLibui() *C.uiAttribute { + otf := C.uiNewOpenTypeFeatures() + defer C.uiFreeOpenTypeFeatures(otf) + for tag, value := range o { + a := byte((tag >> 24) & 0xFF) + b := byte((tag >> 16) & 0xFF) + c := byte((tag >> 8) & 0xFF) + d := byte(tag & 0xFF) + C.uiOpenTypeFeaturesAdd(otf, C.char(a), C.char(b), C.char(c), C.char(d), C.uint32_t(value)) + } + return C.uiNewFeaturesAttribute(otf) +} + +// OpenTypeTag represents a four-byte OpenType feature tag. +type OpenTypeTag uint32 + +// ToOpenTypeTag converts the four characters a, b, c, and d into +// an OpenTypeTag. +func ToOpenTypeTag(a, b, c, d byte) OpenTypeTag { + return (OpenTypeTag(a) << 24) | + (OpenTypeTag(b) << 16) | + (OpenTypeTag(c) << 8) | + OpenTypeTag(d) +} + +func attributeFromLibui(a *C.uiAttribute) Attribute { + switch C.uiAttributeGetType(a) { + case C.uiAttributeTypeFamily: + cf := C.uiAttributeFamily(a) + return TextFamily(C.GoString(cf)) + case C.uiAttributeTypeSize: + return TextSize(C.uiAttributeSize(a)) + case C.uiAttributeTypeWeight: + return TextWeight(C.uiAttributeWeight(a)) + case C.uiAttributeTypeItalic: + return TextItalic(C.uiAttributeItalic(a)) + case C.uiAttributeTypeStretch: + return TextStretch(C.uiAttributeStretch(a)) + case C.uiAttributeTypeColor: + cc := C.pkguiAllocColorDoubles() + defer C.pkguiFreeColorDoubles(cc) + C.uiAttributeColor(a, cc.r, cc.g, cc.b, cc.a) + return TextColor{ + R: float64(*(cc.r)), + G: float64(*(cc.g)), + B: float64(*(cc.b)), + A: float64(*(cc.a)), + } + case C.uiAttributeTypeBackground: + cc := C.pkguiAllocColorDoubles() + defer C.pkguiFreeColorDoubles(cc) + C.uiAttributeColor(a, cc.r, cc.g, cc.b, cc.a) + return TextBackground{ + R: float64(*(cc.r)), + G: float64(*(cc.g)), + B: float64(*(cc.b)), + A: float64(*(cc.a)), + } + case C.uiAttributeTypeUnderline: + return Underline(C.uiAttributeUnderline(a)) + case C.uiAttributeTypeUnderlineColor: + cu := C.pkguiNewUnderlineColor() + defer C.pkguiFreeUnderlineColor(cu) + cc := C.pkguiAllocColorDoubles() + defer C.pkguiFreeColorDoubles(cc) + C.uiAttributeUnderlineColor(a, cu, cc.r, cc.g, cc.b, cc.a) + if *cu == C.uiUnderlineColorCustom { + return UnderlineColorCustom{ + R: float64(*(cc.r)), + G: float64(*(cc.g)), + B: float64(*(cc.b)), + A: float64(*(cc.a)), + } + } + return UnderlineColor(*cu) + case C.uiAttributeTypeFeatures: + // TODO + } + panic("unreachable") +} + +// AttributedString represents a string of UTF-8 text that can +// optionally be embellished with formatting attributes. Package ui +// provides the list of formatting attributes, which cover common +// formatting traits like boldface and color as well as advanced +// typographical features provided by OpenType like superscripts +// and small caps. These attributes can be combined in a variety of +// ways. +// +// Attributes are applied to runs of Unicode codepoints in the string. +// Zero-length runs are elided. Consecutive runs that have the same +// attribute type and value are merged. Each attribute is independent +// of each other attribute; overlapping attributes of different types +// do not split each other apart, but different values of the same +// attribute type do. +// +// The empty string can also be represented by AttributedString, +// but because of the no-zero-length-attribute rule, it will not have +// attributes. +// +// Unlike Go strings, AttributedStrings are mutable. +// +// AttributedString allocates resources within libui, which package +// ui sits on top of. As such, when you are finished with an +// AttributedString, you must free it with Free. Like other things in +// package ui, AttributedString must only be used from the main +// goroutine. +// +// In addition, AttributedString provides facilities for moving +// between grapheme clusters, which represent a character +// from the point of view of the end user. The cursor of a text editor +// is always placed on a grapheme boundary, so you can use these +// features to move the cursor left or right by one "character". +// TODO does uiAttributedString itself need this +// +// AttributedString does not provide enough information to be able +// to draw itself onto a DrawContext or respond to user actions. +// In order to do that, you'll need to use a DrawTextLayout, which +// is built from the combination of an AttributedString and a set of +// layout-specific properties. +type AttributedString struct { + s *C.uiAttributedString +} + +// NewAttributedString creates a new AttributedString from +// initialString. The string will be entirely unattributed. +func NewAttributedString(initialString string) *AttributedString { + cs := C.CString(initialString) + defer freestr(cs) + return &AttributedString{ + s: C.uiNewAttributedString(cs), + } +} + +// Free destroys s. +func (s *AttributedString) Free() { + C.uiFreeAttributedString(s.s) +} + +// String returns the textual content of s. +func (s *AttributedString) String() string { + return C.GoString(C.uiAttributedStringString(s.s)) +} + +// AppendUnattributed adds str to the end of s. The new substring +// will be unattributed. +func (s *AttributedString) AppendUnattributed(str string) { + cs := C.CString(str) + defer freestr(cs) + C.uiAttributedStringAppendUnattributed(s.s, cs) +} + +// InsertAtUnattributed adds str to s at the byte position specified by +// at. The new substring will be unattributed; existing attributes will +// be moved along with their text. +func (s *AttributedString) InsertAtUnattributed(str string, at int) { + cs := C.CString(str) + defer freestr(cs) + C.uiAttributedStringInsertAtUnattributed(s.s, cs, C.size_t(at)) +} + +// Delete deletes the characters and attributes of s in the byte range +// [start, end). +func (s *AttributedString) Delete(start, end int) { + C.uiAttributedStringDelete(s.s, C.size_t(start), C.size_t(end)) +} + +// SetAttribute sets a in the byte range [start, end) of s. Any existing +// attributes in that byte range of the same type are removed. +func (s *AttributedString) SetAttribute(a Attribute, start, end int) { + C.uiAttributedStringSetAttribute(s.s, a.toLibui(), C.size_t(start), C.size_t(end)) +} + +// TODO uiAttributedStringForEachAttribute +// TODO uiAttributedStringNumGraphemes +// TODO uiAttributedStringByteIndexToGrapheme +// TODO uiAttributedStringGraphemeToByteIndex + +// FontDescriptor provides a complete description of a font where +// one is needed. Currently, this means as the default font of a +// DrawTextLayout and as the data returned by FontButton. +type FontDescriptor struct { + Family TextFamily + Size TextSize + Weight TextWeight + Italic TextItalic + Stretch TextStretch +} + +func (d *FontDescriptor) fromLibui(fd *C.uiFontDescriptor) { + d.Family = TextFamily(C.GoString(fd.Family)) + d.Size = TextSize(fd.Size) + d.Weight = TextWeight(fd.Weight) + d.Italic = TextItalic(fd.Italic) + d.Stretch = TextStretch(fd.Stretch) +} + +func (d *FontDescriptor) toLibui() *C.uiFontDescriptor { + fd := C.pkguiNewFontDescriptor() + fd.Family = C.CString(string(d.Family)) + fd.Size = C.double(d.Size) + fd.Weight = C.uiTextWeight(d.Weight) + fd.Italic = C.uiTextItalic(d.Italic) + fd.Stretch = C.uiTextStretch(d.Stretch) + return fd +} + +func freeLibuiFontDescriptor(fd *C.uiFontDescriptor) { + freestr(fd.Family) + C.pkguiFreeFontDescriptor(fd) +} + +// DrawTextLayout is a concrete representation of an +// AttributedString that can be displayed in a DrawContext. +// It includes information important for the drawing of a block of +// text, including the bounding box to wrap the text within, the +// alignment of lines of text within that box, areas to mark as +// being selected, and other things. +// +// Unlike AttributedString, the content of a DrawTextLayout is +// immutable once it has been created. +// +// TODO talk about OS-specific differences with text drawing that libui can't account for... +type DrawTextLayout struct { + tl *C.uiDrawTextLayout +} + +// DrawTextAlign specifies the alignment of lines of text in a +// DrawTextLayout. +// TODO should this really have Draw in the name? +type DrawTextAlign int +const ( + DrawTextAlignLeft DrawTextAlign = iota + DrawTextAlignCenter + DrawTextAlignRight +) + +// DrawTextLayoutParams describes a DrawTextLayout. +// DefaultFont is used to render any text that is not attributed +// sufficiently in String. Width determines the width of the bounding +// box of the text; the height is determined automatically. +type DrawTextLayoutParams struct { + String *AttributedString + DefaultFont *FontDescriptor + Width float64 + Align DrawTextAlign +} + +// DrawNewTextLayout() creates a new DrawTextLayout from +// the given parameters. +func DrawNewTextLayout(p *DrawTextLayoutParams) *DrawTextLayout { + dp := C.pkguiNewDrawTextLayoutParams() + defer C.pkguiFreeDrawTextLayoutParams(dp) + dp.String = p.String.s + dp.DefaultFont = p.DefaultFont.toLibui() + defer freeLibuiFontDescriptor(dp.DefaultFont) + dp.Width = C.double(p.Width) + dp.Align = C.uiDrawTextAlign(p.Align) + return &DrawTextLayout{ + tl: C.uiDrawNewTextLayout(dp), + } +} + +// Free frees tl. The underlying AttributedString is not freed. +func (tl *DrawTextLayout) Free() { + C.uiDrawFreeTextLayout(tl.tl) +} + +// Text draws tl in c with the top-left point of tl at (x, y). +func (c *DrawContext) Text(tl *DrawTextLayout, x, y float64) { + C.uiDrawText(c.c, tl.tl, C.double(x), C.double(y)) +} + +// TODO uiDrawTextLayoutExtents diff --git a/fontbutton.go b/fontbutton.go new file mode 100644 index 0000000..d465411 --- /dev/null +++ b/fontbutton.go @@ -0,0 +1,56 @@ +// 12 december 2015 + +package ui + +import ( + "unsafe" +) + +// #include "pkgui.h" +import "C" + +// FontButton is a Control that represents a button that the user can +// click to select a font. +type FontButton struct { + ControlBase + b *C.uiFontButton + onChanged func(*FontButton) +} + +// NewFontButton creates a new FontButton. +func NewFontButton() *FontButton { + b := new(FontButton) + + b.b = C.uiNewFontButton() + + C.pkguiFontButtonOnChanged(b.b) + + b.ControlBase = NewControlBase(b, uintptr(unsafe.Pointer(b.b))) + return b +} + +// Font returns the font currently selected in the FontButton. +func (b *FontButton) Font() *FontDescriptor { + cfd := C.pkguiNewFontDescriptor() + defer C.pkguiFreeFontDescriptor(cfd) + C.uiFontButtonFont(b.b, cfd) + defer C.uiFreeFontButtonFont(cfd) + fd := &FontDescriptor{} + fd.fromLibui(cfd) + return fd +} + +// OnChanged registers f to be run when the user changes the +// currently selected font in the FontButton. Only one function can +// be registered at a time. +func (b *FontButton) OnChanged(f func(*FontButton)) { + b.onChanged = f +} + +//export pkguiDoFontButtonOnChanged +func pkguiDoFontButtonOnChanged(bb *C.uiFontButton, data unsafe.Pointer) { + b := ControlFromLibui(uintptr(unsafe.Pointer(bb))).(*FontButton) + if b.onChanged != nil { + b.onChanged(b) + } +} diff --git a/pkgui.c b/pkgui.c index 5d0d55d..081c956 100644 --- a/pkgui.c +++ b/pkgui.c @@ -42,14 +42,6 @@ void pkguiColorButtonOnChanged(uiColorButton *c) uiColorButtonOnChanged(c, pkguiDoColorButtonOnChanged, NULL); } -typedef struct pkguiColorDoubles pkguiColorDoubles; -struct pkguiColorDoubles { - double *r; - double *g; - double *b; - double *a; -}; - pkguiColorDoubles pkguiAllocColorDoubles(void) { pkguiColorDoubles c; @@ -96,6 +88,11 @@ void pkguiEntryOnChanged(uiEntry *e) uiEntryOnChanged(e, pkguiDoEntryOnChanged, NULL); } +void pkguiFontButtonOnChanged(uiFontButton *b) +{ + uiFontButtonOnChanged(b, pkguiDoFontButtonOnChanged, NULL); +} + void pkguiMultilineEntryOnChanged(uiMultilineEntry *e) { uiMultilineEntryOnChanged(e, pkguiDoMultilineEntryOnChanged, NULL); @@ -179,3 +176,33 @@ void pkguiFreeMatrix(uiDrawMatrix *m) { free(m); } + +uiUnderlineColor *pkguiNewUnderlineColor(void) +{ + return (uiUnderlineColor *) pkguiAlloc(sizeof (uiUnderlineColor)); +} + +void pkguiFreeUnderlineColor(uiUnderlineColor *c) +{ + free(c); +} + +uiFontDescriptor *pkguiNewFontDescriptor(void) +{ + return (uiFontDescriptor *) pkguiAlloc(sizeof (uiFontDescriptor)); +} + +void pkguiFreeFontDescriptor(uiFontDescriptor *fd) +{ + free(fd); +} + +uiDrawTextLayoutParams *pkguiNewDrawTextLayoutParams(void) +{ + return (uiDrawTextLayoutParams *) pkguiAlloc(sizeof (uiDrawTextLayoutParams)); +} + +void pkguiFreeDrawTextLayoutParams(uiDrawTextLayoutParams *p) +{ + free(p); +} diff --git a/pkgui.h b/pkgui.h index d421965..44cd6b3 100644 --- a/pkgui.h +++ b/pkgui.h @@ -48,6 +48,9 @@ extern void pkguiEditableComboboxOnChanged(uiEditableCombobox *c); // entry.go extern void pkguiEntryOnChanged(uiEntry *e); +// fontbutton.go +extern void pkguiFontButtonOnChanged(uiFontButton *b); + // multilineentry.go extern void pkguiMultilineEntryOnChanged(uiMultilineEntry *e); @@ -74,4 +77,12 @@ extern void pkguiSetDash(double *dashes, size_t i, double dash); extern uiDrawMatrix *pkguiAllocMatrix(void); extern void pkguiFreeMatrix(uiDrawMatrix *m); +// drawtext.go +extern uiUnderlineColor *pkguiNewUnderlineColor(void); +extern void pkguiFreeUnderlineColor(uiUnderlineColor *c); +extern uiFontDescriptor *pkguiNewFontDescriptor(void); +extern void pkguiFreeFontDescriptor(uiFontDescriptor *fd); +extern uiDrawTextLayoutParams *pkguiNewDrawTextLayoutParams(void); +extern void pkguiFreeDrawTextLayoutParams(uiDrawTextLayoutParams *p); + #endif -- cgit v1.2.3