diff options
| author | Pietro Gagliardi <[email protected]> | 2018-08-26 09:55:07 -0400 |
|---|---|---|
| committer | Pietro Gagliardi <[email protected]> | 2018-08-26 09:55:07 -0400 |
| commit | 62ac2527732a01dfa6bd2c9523215c0ba3816641 (patch) | |
| tree | 84244a69e048f79e4d9f134c121f4cf581200986 /BBB_GOFILES/drawtext.go | |
| parent | a5a00c644c08a6e0f52740c3f2a280977929a285 (diff) | |
Moved all the Go files out of the way again, this time so we can migrate them to more proper cgo usage.
Diffstat (limited to 'BBB_GOFILES/drawtext.go')
| -rw-r--r-- | BBB_GOFILES/drawtext.go | 554 |
1 files changed, 554 insertions, 0 deletions
diff --git a/BBB_GOFILES/drawtext.go b/BBB_GOFILES/drawtext.go new file mode 100644 index 0000000..1cd438c --- /dev/null +++ b/BBB_GOFILES/drawtext.go @@ -0,0 +1,554 @@ +// 12 august 2018 + +package ui + +// #include <stdlib.h> +// #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 |
