diff options
Diffstat (limited to 'draw.go')
| -rw-r--r-- | draw.go | 834 |
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) -} |
