summaryrefslogtreecommitdiff
path: root/draw.go
diff options
context:
space:
mode:
Diffstat (limited to 'draw.go')
-rw-r--r--draw.go834
1 files changed, 0 insertions, 834 deletions
diff --git a/draw.go b/draw.go
deleted file mode 100644
index eb4158d..0000000
--- a/draw.go
+++ /dev/null
@@ -1,834 +0,0 @@
-// 13 december 2015
-
-package ui
-
-// #include <stdlib.h>
-// #include "ui.h"
-// // TODO figure this one out
-// extern void *uimalloc(size_t);
-// static uiDrawBrush *newBrush(void)
-// {
-// uiDrawBrush *b;
-//
-// b = (uiDrawBrush *) uimalloc(sizeof (uiDrawBrush));
-// return b;
-// }
-// static uiDrawBrushGradientStop *newStops(size_t n)
-// {
-// uiDrawBrushGradientStop *stops;
-//
-// stops = (uiDrawBrushGradientStop *) malloc(n * sizeof (uiDrawBrushGradientStop));
-// // TODO
-// return stops;
-// }
-// static void setStop(uiDrawBrushGradientStop *stops, size_t i, double pos, double r, double g, double b, double a)
-// {
-// stops[i].Pos = pos;
-// stops[i].R = r;
-// stops[i].G = g;
-// stops[i].B = b;
-// stops[i].A = a;
-// }
-// static void freeBrush(uiDrawBrush *b)
-// {
-// if (b->Type == uiDrawBrushTypeLinearGradient || b->Type == uiDrawBrushTypeRadialGradient)
-// free(b->Stops);
-// free(b);
-// }
-// static uiDrawStrokeParams *newStrokeParams(void)
-// {
-// uiDrawStrokeParams *b;
-//
-// b = (uiDrawStrokeParams *) malloc(sizeof (uiDrawStrokeParams));
-// // TODO
-// return b;
-// }
-// static double *newDashes(size_t n)
-// {
-// double *dashes;
-//
-// dashes = (double *) malloc(n * sizeof (double));
-// // TODO
-// return dashes;
-// }
-// static void setDash(double *dashes, size_t i, double dash)
-// {
-// dashes[i] = dash;
-// }
-// static void freeStrokeParams(uiDrawStrokeParams *sp)
-// {
-// if (sp->Dashes != NULL)
-// free(sp->Dashes);
-// free(sp);
-// }
-// static uiDrawMatrix *newMatrix(void)
-// {
-// uiDrawMatrix *m;
-//
-// m = (uiDrawMatrix *) malloc(sizeof (uiDrawMatrix));
-// // TODO
-// return m;
-// }
-// static void freeMatrix(uiDrawMatrix *m)
-// {
-// free(m);
-// }
-// static uiDrawTextFontDescriptor *newFontDescriptor(void)
-// {
-// uiDrawTextFontDescriptor *desc;
-//
-// desc = (uiDrawTextFontDescriptor *) malloc(sizeof (uiDrawTextFontDescriptor));
-// // TODO
-// return desc;
-// }
-// static uiDrawTextFont *newFont(uiDrawTextFontDescriptor *desc)
-// {
-// uiDrawTextFont *font;
-//
-// font = uiDrawLoadClosestFont(desc);
-// free((char *) (desc->Family));
-// free(desc);
-// return font;
-// }
-// static uiDrawTextLayout *newTextLayout(char *text, uiDrawTextFont *defaultFont, double width)
-// {
-// uiDrawTextLayout *layout;
-//
-// layout = uiDrawNewTextLayout(text, defaultFont, width);
-// free(text);
-// return layout;
-// }
-// static uiDrawTextFontMetrics *newFontMetrics(void)
-// {
-// uiDrawTextFontMetrics *m;
-//
-// m = (uiDrawTextFontMetrics *) malloc(sizeof (uiDrawTextFontMetrics));
-// // TODO
-// return m;
-// }
-// static void freeFontMetrics(uiDrawTextFontMetrics *m)
-// {
-// free(m);
-// }
-// static double *newDouble(void)
-// {
-// double *d;
-//
-// d = (double *) malloc(sizeof (double));
-// // TODO
-// return d;
-// }
-// static void freeDoubles(double *a, double *b)
-// {
-// free(a);
-// free(b);
-// }
-import "C"
-
-// BUG(andlabs): Ideally, all the drawing APIs should be in another package ui/draw (they all have the "uiDraw" prefix in C to achieve a similar goal of avoiding confusing programmers via namespace pollution); managing the linkage of the libui shared library itself across multiple packages is likely going to be a pain, though. (Custom controls implemented using libui won't have this issue, as they *should* only need libui present when linking the shared object, not when linking the Go wrapper. I'm not sure; I'd have to find out first.)
-
-// Path represents a geometric path in a drawing context.
-// This is the basic unit of drawing: all drawing operations consist of
-// forming a path, then stroking, filling, or clipping to that path.
-// A path is an OS resource; you must explicitly free it when finished.
-// Paths consist of multiple figures. Once you have added all the
-// figures to a path, you must "end" the path to make it ready to draw
-// with.
-// TODO rewrite all that
-//
-// Or more visually, the lifecycle of a Path is
-// p := NewPath()
-// for every figure {
-// p.NewFigure(...) // or NewFigureWithArc
-// p.LineTo(...) // any number of these in any order
-// p.ArcTo(...)
-// p.BezierTo(...)
-// if figure should be closed {
-// p.CloseFigure()
-// }
-// }
-// p.End()
-// // ...
-// dp.Context.Stroke(p, ...) // any number of these in any order
-// dp.Context.Fill(p, ...)
-// dp.Context.Clip(p)
-// // ...
-// p.Free() // when done with the path
-//
-// A Path also defines its fill mode. (This should ideally be a fill
-// parameter, but some implementations prevent it.)
-// TODO talk about fill modes
-type Path struct {
- p *C.uiDrawPath
-}
-
-// TODO
-//
-// TODO disclaimer
-type FillMode uint
-const (
- Winding FillMode = iota
- Alternate
-)
-
-// NewPath creates a new Path with the given fill mode.
-func NewPath(fillMode FillMode) *Path {
- var fm C.uiDrawFillMode
-
- switch fillMode {
- case Winding:
- fm = C.uiDrawFillModeWinding
- case Alternate:
- fm = C.uiDrawFillModeAlternate
- default:
- panic("invalid fill mode passed to ui.NewPath()")
- }
- return &Path{
- p: C.uiDrawNewPath(fm),
- }
-}
-
-// Free destroys a Path. After calling Free the Path cannot be used.
-func (p *Path) Free() {
- C.uiDrawFreePath(p.p)
-}
-
-// NewFigure starts a new figure in the Path. The current point
-// is set to the given point.
-func (p *Path) NewFigure(x float64, y float64) {
- C.uiDrawPathNewFigure(p.p, C.double(x), C.double(y))
-}
-
-// NewFigureWithArc starts a new figure in the Path and adds an arc
-// as the first element of the figure. Unlike ArcTo, NewFigureWithArc
-// does not draw an initial line segment. Otherwise, see ArcTo.
-func (p *Path) NewFigureWithArc(xCenter float64, yCenter float64, radius float64, startAngle float64, sweep float64, isNegative bool) {
- C.uiDrawPathNewFigureWithArc(p.p,
- C.double(xCenter), C.double(yCenter),
- C.double(radius),
- C.double(startAngle), C.double(sweep),
- frombool(isNegative))
-}
-
-// LineTo adds a line to the current figure of the Path starting from
-// the current point and ending at the given point. The current point
-// is set to the ending point.
-func (p *Path) LineTo(x float64, y float64) {
- C.uiDrawPathLineTo(p.p, C.double(x), C.double(y))
-}
-
-// ArcTo adds a circular arc to the current figure of the Path.
-// You pass it the center of the arc, its radius in radians, the starting
-// angle (couterclockwise) in radians, and the number of radians the
-// arc should sweep (counterclockwise). A line segment is drawn from
-// the current point to the start of the arc. The current point is set to
-// the end of the arc.
-func (p *Path) ArcTo(xCenter float64, yCenter float64, radius float64, startAngle float64, sweep float64, isNegative bool) {
- C.uiDrawPathArcTo(p.p,
- C.double(xCenter), C.double(yCenter),
- C.double(radius),
- C.double(startAngle), C.double(sweep),
- frombool(isNegative))
-}
-
-// BezierTo adds a cubic Bezier curve to the current figure of the Path.
-// Its start point is the current point. c1x and c1y are the first control
-// point. c2x and c2y are the second control point. endX and endY
-// are the end point. The current point is set to the end point.
-func (p *Path) BezierTo(c1x float64, c1y float64, c2x float64, c2y float64, endX float64, endY float64) {
- C.uiDrawPathBezierTo(p.p,
- C.double(c1x), C.double(c1y),
- C.double(c2x), C.double(c2y),
- C.double(endX), C.double(endY))
-}
-
-// CloseFigure draws a line segment from the current point of the
-// current figure of the Path back to its initial point. After calling this,
-// the current figure is over and you must either start a new figure
-// or end the Path. If this is not called and you start a new figure or
-// end the Path, then the current figure will not have this closing line
-// segment added to it (but the figure will still be over).
-func (p *Path) CloseFigure() {
- C.uiDrawPathCloseFigure(p.p)
-}
-
-// AddRectangle creates a new figure in the Path that consists entirely
-// of a rectangle whose top-left corner is at the given point and whose
-// size is the given size. The rectangle is a closed figure; you must
-// either start a new figure or end the Path after calling this method.
-func (p *Path) AddRectangle(x float64, y float64, width float64, height float64) {
- C.uiDrawPathAddRectangle(p.p, C.double(x), C.double(y), C.double(width), C.double(height))
-}
-
-// End ends the current Path. You cannot add figures to a Path that has
-// been ended. You cannot draw with a Path that has not been ended.
-func (p *Path) End() {
- C.uiDrawPathEnd(p.p)
-}
-
-// DrawContext represents a drawing surface that you can draw to.
-// At present the only DrawContexts are surfaces associated with
-// Areas and are provided by package ui; see AreaDrawParams.
-type DrawContext struct {
- c *C.uiDrawContext
-}
-
-// BrushType defines the various types of brushes.
-//
-// TODO disclaimer
-type BrushType int
-const (
- Solid BrushType = iota
- LinearGradient
- RadialGradient
- Image // presently unimplemented
-)
-
-// TODO
-//
-// TODO disclaimer
-// TODO rename these to put LineCap at the beginning? or just Cap?
-type LineCap int
-const (
- FlatCap LineCap = iota
- RoundCap
- SquareCap
-)
-
-// TODO
-//
-// TODO disclaimer
-type LineJoin int
-const (
- MiterJoin LineJoin = iota
- RoundJoin
- BevelJoin
-)
-
-// TODO document
-const DefaultMiterLimit = 10.0
-
-// TODO
-type Brush struct {
- Type BrushType
-
- // If Type is Solid.
- // TODO
- R float64
- G float64
- B float64
- A float64
-
- // If Type is LinearGradient or RadialGradient.
- // TODO
- X0 float64 // start point for both
- Y0 float64
- X1 float64 // linear: end point; radial: circle center
- Y1 float64
- OuterRadius float64 // for radial gradients only
- Stops []GradientStop
-}
-
-// TODO
-type GradientStop struct {
- Pos float64 // between 0 and 1 inclusive
- R float64
- G float64
- B float64
- A float64
-}
-
-func (b *Brush) toC() *C.uiDrawBrush {
- cb := C.newBrush()
- cb.Type = C.uiDrawBrushType(b.Type)
- switch b.Type {
- case Solid:
- cb.R = C.double(b.R)
- cb.G = C.double(b.G)
- cb.B = C.double(b.B)
- cb.A = C.double(b.A)
- case LinearGradient, RadialGradient:
- cb.X0 = C.double(b.X0)
- cb.Y0 = C.double(b.Y0)
- cb.X1 = C.double(b.X1)
- cb.Y1 = C.double(b.Y1)
- cb.OuterRadius = C.double(b.OuterRadius)
- cb.NumStops = C.size_t(len(b.Stops))
- cb.Stops = C.newStops(cb.NumStops)
- for i, s := range b.Stops {
- C.setStop(cb.Stops, C.size_t(i),
- C.double(s.Pos),
- C.double(s.R),
- C.double(s.G),
- C.double(s.B),
- C.double(s.A))
- }
- case Image:
- panic("unimplemented")
- default:
- panic("invalid brush type in Brush.toC()")
- }
- return cb
-}
-
-// TODO
-type StrokeParams struct {
- Cap LineCap
- Join LineJoin
- Thickness float64
- MiterLimit float64
- Dashes []float64
- DashPhase float64
-}
-
-func (sp *StrokeParams) toC() *C.uiDrawStrokeParams {
- csp := C.newStrokeParams()
- csp.Cap = C.uiDrawLineCap(sp.Cap)
- csp.Join = C.uiDrawLineJoin(sp.Join)
- csp.Thickness = C.double(sp.Thickness)
- csp.MiterLimit = C.double(sp.MiterLimit)
- csp.Dashes = nil
- csp.NumDashes = C.size_t(len(sp.Dashes))
- if csp.NumDashes != 0 {
- csp.Dashes = C.newDashes(csp.NumDashes)
- for i, d := range sp.Dashes {
- C.setDash(csp.Dashes, C.size_t(i), C.double(d))
- }
- }
- csp.DashPhase = C.double(sp.DashPhase)
- return csp
-}
-
-// TODO
-func (c *DrawContext) Stroke(p *Path, b *Brush, sp *StrokeParams) {
- cb := b.toC()
- csp := sp.toC()
- C.uiDrawStroke(c.c, p.p, cb, csp)
- C.freeBrush(cb)
- C.freeStrokeParams(csp)
-}
-
-// TODO
-func (c *DrawContext) Fill(p *Path, b *Brush) {
- cb := b.toC()
- C.uiDrawFill(c.c, p.p, cb)
- C.freeBrush(cb)
-}
-
-// TODO
-// TODO should the methods of these return self for chaining?
-type Matrix struct {
- M11 float64
- M12 float64
- M21 float64
- M22 float64
- M31 float64
- M32 float64
-}
-
-// TODO identity matrix
-func NewMatrix() *Matrix {
- m := new(Matrix)
- m.SetIdentity()
- return m
-}
-
-// TODO
-func (m *Matrix) SetIdentity() {
- m.M11 = 1
- m.M12 = 0
- m.M21 = 0
- m.M22 = 1
- m.M31 = 0
- m.M32 = 0
-}
-
-func (m *Matrix) toC() *C.uiDrawMatrix {
- cm := C.newMatrix()
- cm.M11 = C.double(m.M11)
- cm.M12 = C.double(m.M12)
- cm.M21 = C.double(m.M21)
- cm.M22 = C.double(m.M22)
- cm.M31 = C.double(m.M31)
- cm.M32 = C.double(m.M32)
- return cm
-}
-
-func (m *Matrix) fromC(cm *C.uiDrawMatrix) {
- m.M11 = float64(cm.M11)
- m.M12 = float64(cm.M12)
- m.M21 = float64(cm.M21)
- m.M22 = float64(cm.M22)
- m.M31 = float64(cm.M31)
- m.M32 = float64(cm.M32)
- C.freeMatrix(cm)
-}
-
-// TODO
-func (m *Matrix) Translate(x float64, y float64) {
- cm := m.toC()
- C.uiDrawMatrixTranslate(cm, C.double(x), C.double(y))
- m.fromC(cm)
-}
-
-// TODO
-func (m *Matrix) Scale(xCenter float64, yCenter float64, x float64, y float64) {
- cm := m.toC()
- C.uiDrawMatrixScale(cm,
- C.double(xCenter), C.double(yCenter),
- C.double(x), C.double(y))
- m.fromC(cm)
-}
-
-// TODO
-func (m *Matrix) Rotate(x float64, y float64, amount float64) {
- cm := m.toC()
- C.uiDrawMatrixRotate(cm, C.double(x), C.double(y), C.double(amount))
- m.fromC(cm)
-}
-
-// TODO
-func (m *Matrix) Skew(x float64, y float64, xamount float64, yamount float64) {
- cm := m.toC()
- C.uiDrawMatrixSkew(cm,
- C.double(x), C.double(y),
- C.double(xamount), C.double(yamount))
- m.fromC(cm)
-}
-
-// TODO
-func (m *Matrix) Multiply(m2 *Matrix) {
- cm := m.toC()
- cm2 := m2.toC()
- C.uiDrawMatrixMultiply(cm, cm2)
- C.freeMatrix(cm2)
- m.fromC(cm)
-}
-
-// TODO
-func (m *Matrix) Invertible() bool {
- cm := m.toC()
- res := C.uiDrawMatrixInvertible(cm)
- C.freeMatrix(cm)
- return tobool(res)
-}
-
-// TODO
-//
-// If m is not invertible, false is returned and m is left unchanged.
-func (m *Matrix) Invert() bool {
- cm := m.toC()
- res := C.uiDrawMatrixInvert(cm)
- m.fromC(cm)
- return tobool(res)
-}
-
-// TODO unimplemented
-func (m *Matrix) TransformPoint(x float64, y float64) (xout float64, yout float64) {
- panic("TODO")
-}
-
-// TODO unimplemented
-func (m *Matrix) TransformSize(x float64, y float64) (xout float64, yout float64) {
- panic("TODO")
-}
-
-// TODO
-func (c *DrawContext) Transform(m *Matrix) {
- cm := m.toC()
- C.uiDrawTransform(c.c, cm)
- C.freeMatrix(cm)
-}
-
-// TODO
-func (c *DrawContext) Clip(p *Path) {
- C.uiDrawClip(c.c, p.p)
-}
-
-// TODO
-func (c *DrawContext) Save() {
- C.uiDrawSave(c.c)
-}
-
-// TODO
-func (c *DrawContext) Restore() {
- C.uiDrawRestore(c.c)
-}
-
-// FontFamilies represents an enumerator over the font families
-// available for use by package ui. A FontFamilies object behaves
-// similarly to a []string, except that since family names are loaded
-// on demand (depending on the operating system), it is not an
-// actual []string. You call ListFontFamilies to obtain a FontFamilies
-// object, which should reflect the available fonts at the time of the
-// call (TODO verify). Use NumFamilies to get the number of families,
-// and Family to get the name of a given family by index. When
-// finished, call Free.
-//
-// There is no guarantee that the list of families is sorted. You will
-// need to do sorting yourself if you need it.
-//
-// TODO thread affinity
-type FontFamilies struct {
- ff *C.uiDrawFontFamilies
-}
-
-// ListFontFamilies creates a new FontFamilies object ready for use.
-func ListFontFamilies() *FontFamilies {
- return &FontFamilies{
- ff: C.uiDrawListFontFamilies(),
- }
-}
-
-// Free destroys a FontFamilies. After calling Free, the FontFamilies
-// cannot be used.
-func (f *FontFamilies) Free() {
- C.uiDrawFreeFontFamilies(f.ff)
-}
-
-// NumFamilies returns the number of font families available.
-func (f *FontFamilies) NumFamilies() int {
- return int(C.uiDrawFontFamiliesNumFamilies(f.ff))
-}
-
-// Family returns the name of the nth family in the list.
-func (f *FontFamilies) Family(n int) string {
- cname := C.uiDrawFontFamiliesFamily(f.ff, C.uintmax_t(n))
- name := C.GoString(cname)
- C.uiFreeText(cname)
- return name
-}
-
-// TextWeight defines the various text weights, in order of
-// increasing weight.
-//
-// Note that if you leave this field unset, it will default to
-// TextWeightThin. If you want the normal font weight, explicitly
-// use the constant TextWeightNormal instead.
-// TODO realign these?
-//
-// TODO disclaimer
-type TextWeight int
-const (
- TextWeightThin TextWeight = iota
- TextWeightUltraLight
- TextWeightLight
- TextWeightBook
- TextWeightNormal
- TextWeightMedium
- TextWeightSemiBold
- TextWeightBold
- TextWeightUtraBold
- TextWeightHeavy
- TextWeightUltraHeavy
-)
-
-// TextItalic defines the various text italic modes.
-//
-// TODO disclaimer
-type TextItalic int
-const (
- TextItalicNormal TextItalic = iota
- TextItalicOblique // merely slanted text
- TextItalicItalic // true italics
-)
-
-// TextStretch defines the various text stretches, in order of
-// increasing wideness.
-//
-// Note that if you leave this field unset, it will default to
-// TextStretchUltraCondensed. If you want the normal font
-// stretch, explicitly use the constant TextStretchNormal
-// instead.
-// TODO realign these?
-//
-// TODO disclaimer
-type TextStretch int
-const (
- TextStretchUltraCondensed TextStretch = iota
- TextStretchExtraCondensed
- TextStretchCondensed
- TextStretchSemiCondensed
- TextStretchNormal
- TextStretchSemiExpanded
- TextStretchExpanded
- TextStretchExtraExpanded
- TextStretchUltraExpanded
-)
-
-// FontDescriptor describes a Font.
-type FontDescriptor struct {
- Family string
- Size float64 // as a text size, for instance 12 for a 12-point font
- Weight TextWeight
- Italic TextItalic
- Stretch TextStretch
-}
-
-// Font represents an actual font that can be drawn with.
-type Font struct {
- f *C.uiDrawTextFont
-}
-
-// LoadClosestFont loads a Font.
-//
-// You pass the properties of the ideal font you want to load in the
-// FontDescriptor you pass to this function. If the requested font
-// is not available on the system, the closest matching font is used.
-// This means that, for instance, if you specify a Weight of
-// TextWeightUltraHeavy and the heaviest weight available for the
-// chosen font family is actually TextWeightBold, that will be used
-// instead. The specific details of font matching beyond this
-// description are implementation defined. This also means that
-// getting a descriptor back out of a Font may return a different
-// desriptor.
-//
-// TODO guarantee that passing *that* back into LoadClosestFont() returns the same font
-func LoadClosestFont(desc *FontDescriptor) *Font {
- d := C.newFontDescriptor() // both of these are freed by C.newFont()
- d.Family = C.CString(desc.Family)
- d.Size = C.double(desc.Size)
- d.Weight = C.uiDrawTextWeight(desc.Weight)
- d.Italic = C.uiDrawTextItalic(desc.Italic)
- d.Stretch = C.uiDrawTextStretch(desc.Stretch)
- return &Font{
- f: C.newFont(d),
- }
-}
-
-// Free destroys a Font. After calling Free the Font cannot be used.
-func (f *Font) Free() {
- C.uiDrawFreeTextFont(f.f)
-}
-
-// Handle returns the OS font object that backs this Font. On OSs
-// that use reference counting for font objects, Handle does not
-// increment the reference count; you are sharing package ui's
-// reference.
-//
-// On Windows this is a pointer to an IDWriteFont.
-//
-// On Unix systems this is a pointer to a PangoFont.
-//
-// On OS X this is a CTFontRef.
-func (f *Font) Handle() uintptr {
- return uintptr(C.uiDrawTextFontHandle(f.f))
-}
-
-// Describe returns the FontDescriptor that most closely matches
-// this Font.
-// TODO guarantees about idempotency
-// TODO rewrite that first sentence
-func (f *Font) Describe() *FontDescriptor {
- panic("TODO unimplemented")
-}
-
-// FontMetrics holds various measurements about a Font.
-// All metrics are in the same point units used for drawing.
-type FontMetrics struct {
- // Ascent is the ascent of the font; that is, the distance from
- // the top of the character cell to the baseline.
- Ascent float64
-
- // Descent is the descent of the font; that is, the distance from
- // the baseline to the bottom of the character cell. The sum of
- // Ascent and Descent is the height of the character cell (and
- // thus, the maximum height of a line of text).
- Descent float64
-
- // Leading is the amount of space the font designer suggests
- // to have between lines (between the bottom of the first line's
- // character cell and the top of the second line's character cell).
- // This is a suggestion; it is chosen by the font designer to
- // improve legibility.
- Leading float64
-
- // TODO figure out what these are
- UnderlinePos float64
- UnderlineThickness float64
-}
-
-// Metrics returns metrics about the given Font.
-func (f *Font) Metrics() *FontMetrics {
- m := new(FontMetrics)
- mm := C.newFontMetrics()
- C.uiDrawTextFontGetMetrics(f.f, mm)
- m.Ascent = float64(mm.Ascent)
- m.Descent = float64(mm.Descent)
- m.Leading = float64(mm.Leading)
- m.UnderlinePos = float64(mm.UnderlinePos)
- m.UnderlineThickness = float64(mm.UnderlineThickness)
- C.freeFontMetrics(mm)
- return m
-}
-
-// TextLayout is the entry point for formatting a block of text to be
-// drawn onto a DrawContext.
-//
-// The block of text to lay out and the default font that is used if no
-// font attributes are applied to a given character are provided
-// at TextLayout creation time and cannot be changed later.
-// However, you may add attributes to various points of the text
-// at any time, even after drawing the text once (unlike a DrawPath).
-// Some of these attributes also have initial values; refer to each
-// method to see what they are.
-//
-// The block of text can either be a single line or multiple
-// word-wrapped lines, each with a given maximum width.
-type TextLayout struct {
- l *C.uiDrawTextLayout
-}
-
-// NewTextLayout creates a new TextLayout.
-// For details on the width parameter, see SetWidth.
-func NewTextLayout(text string, defaultFont *Font, width float64) *TextLayout {
- l := new(TextLayout)
- ctext := C.CString(text) // freed by C.newTextLayout()
- l.l = C.newTextLayout(ctext, defaultFont.f, C.double(width))
- return l
-}
-
-// Free destroys a TextLayout. After calling Free the TextLayout
-// cannot be used.
-func (l *TextLayout) Free() {
- C.uiDrawFreeTextLayout(l.l)
-}
-
-// SetWidth sets the maximum width of the lines of text in a
-// TextLayout. If the given width is negative, then the TextLayout
-// will draw as a single line of text instead.
-func (l *TextLayout) SetWidth(width float64) {
- C.uiDrawTextLayoutSetWidth(l.l, C.double(width))
-}
-
-// Extents returns the width and height that the TextLayout will
-// actually take up when drawn. This measures full line allocations,
-// even if no glyph reaches to the top of its ascent or bottom of its
-// descent; it does not return a "best fit" rectnagle for the points that
-// are actually drawn.
-//
-// For a single-line TextLayout (where the width is negative), if there
-// are no font changes throughout the TextLayout, then the height
-// returned by TextLayout is equivalent to the sum of the ascent and
-// descent of its default font's metrics. Or in other words, after
-// f := ui.LoadClosestFont(...)
-// l := ui.NewTextLayout("text", f, -1)
-// metrics := f.Metrics()
-// _, height := l.Extents()
-// metrics.Ascent+metrics.Descent and height are equivalent.
-func (l *TextLayout) Extents() (width float64, height float64) {
- cwidth := C.newDouble()
- cheight := C.newDouble()
- C.uiDrawTextLayoutExtents(l.l, cwidth, cheight)
- width = float64(*cwidth)
- height = float64(*cheight)
- C.freeDoubles(cwidth, cheight)
- return width, height
-}
-
-// Text draws the given TextLayout onto c at the given point.
-// The point refers to the top-left corner of the text.
-// (TODO bounding box or typographical extent?)
-func (c *DrawContext) Text(x float64, y float64, layout *TextLayout) {
- C.uiDrawText(c.c, C.double(x), C.double(y), layout.l)
-}