2015-12-13 11:52:16 -06:00
// 13 december 2015
2015-12-13 11:53:37 -06:00
package ui
2015-12-13 11:52:16 -06:00
2015-12-20 11:24:10 -06:00
// #include <stdlib.h>
2015-12-13 11:52:16 -06:00
// #include "ui.h"
2015-12-20 11:24:10 -06:00
// static uiDrawBrush *newBrush(void)
// {
// uiDrawBrush *b;
//
// b = (uiDrawBrush *) malloc(sizeof (uiDrawBrush));
// // TODO
// 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);
// }
2015-12-21 22:36:09 -06:00
// static uiDrawMatrix *newMatrix(void)
// {
// uiDrawMatrix *m;
//
// m = (uiDrawMatrix *) malloc(sizeof (uiDrawMatrix));
// // TODO
// return m;
// }
// static void freeMatrix(uiDrawMatrix *m)
// {
// free(m);
// }
2016-01-12 17:34:51 -06:00
// static uiDrawTextFontDescriptor *newFontDescriptor(void)
2016-01-09 19:57:35 -06:00
// {
2016-01-12 17:34:51 -06:00
// uiDrawTextFontDescriptor *desc;
2016-01-09 19:57:35 -06:00
//
2016-01-12 17:34:51 -06:00
// desc = (uiDrawTextFontDescriptor *) malloc(sizeof (uiDrawTextFontDescriptor));
2016-01-09 19:57:35 -06:00
// // TODO
2016-01-12 17:34:51 -06:00
// return desc;
2016-01-09 19:57:35 -06:00
// }
2016-01-12 17:34:51 -06:00
// static uiDrawTextFont *newFont(uiDrawTextFontDescriptor *desc)
// {
// uiDrawTextFont *font;
//
// font = uiDrawLoadClosestFont(desc);
// free((char *) (desc->Family));
// free(desc);
// return font;
// }
2016-01-16 15:56:58 -06:00
// static uiDrawTextLayout *newTextLayout(char *text, uiDrawTextFont *defaultFont, double width)
2016-01-09 19:57:35 -06:00
// {
// uiDrawTextLayout *layout;
//
2016-01-16 15:56:58 -06:00
// layout = uiDrawNewTextLayout(text, defaultFont, width);
2016-01-09 19:57:35 -06:00
// free(text);
// return layout;
// }
2016-01-13 16:57:23 -06:00
// static uiDrawTextFontMetrics *newFontMetrics(void)
// {
// uiDrawTextFontMetrics *m;
//
// m = (uiDrawTextFontMetrics *) malloc(sizeof (uiDrawTextFontMetrics));
// // TODO
// return m;
// }
// static void freeFontMetrics(uiDrawTextFontMetrics *m)
// {
// free(m);
// }
2016-01-16 15:56:58 -06:00
// 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);
// }
2015-12-13 11:52:16 -06:00
import "C"
2015-12-23 00:22:07 -06:00
// 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.)
2015-12-13 11:52:16 -06:00
// 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
2015-12-16 13:03:47 -06:00
//
// A Path also defines its fill mode. (This should ideally be a fill
// parameter, but some implementations prevent it.)
// TODO talk about fill modes
2015-12-13 11:52:16 -06:00
type Path struct {
p * C . uiDrawPath
}
2015-12-16 13:03:47 -06:00
// TODO
2016-01-09 19:57:35 -06:00
//
// TODO disclaimer
2015-12-16 13:03:47 -06:00
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()" )
}
2015-12-13 11:52:16 -06:00
return & Path {
2015-12-16 13:03:47 -06:00
p : C . uiDrawNewPath ( fm ) ,
2015-12-13 11:52:16 -06:00
}
}
// 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
}
2015-12-20 11:24:10 -06:00
// BrushType defines the various types of brushes.
//
// TODO disclaimer
type BrushType int
const (
Solid BrushType = iota
LinearGradient
RadialGradient
Image // presently unimplemented
)
// TODO
//
// TODO disclaimer
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
type Matrix struct {
M11 float64
M12 float64
M21 float64
M22 float64
M31 float64
M32 float64
}
// TODO identity matrix
func NewMatrix ( ) * Matrix {
m := new ( Matrix )
2015-12-21 22:36:09 -06:00
m . SetIdentity ( )
return m
}
// TODO
func ( m * Matrix ) SetIdentity ( ) {
2015-12-20 11:24:10 -06:00
m . M11 = 1
2015-12-21 22:36:09 -06:00
m . M12 = 0
m . M21 = 0
2015-12-20 11:24:10 -06:00
m . M22 = 1
2015-12-21 22:36:09 -06:00
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" )
2015-12-20 11:24:10 -06:00
}
// TODO
2015-12-21 22:36:09 -06:00
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 )
}
2015-12-23 00:12:43 -06:00
// FontFamilies represents an enumerator over the font families
2015-12-23 00:14:33 -06:00
// available for use by package ui. A FontFamilies object behaves
2015-12-23 00:12:43 -06:00
// similarly to a []string, except that since family names are loaded
2015-12-23 00:16:18 -06:00
// 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.
2015-12-23 00:12:43 -06:00
//
// 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
}
2016-01-09 19:57:35 -06:00
// 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
)
// TODO put TextGravity here
2016-01-12 17:34:51 -06:00
// FontDescriptor describes a Font.
type FontDescriptor struct {
2016-01-09 19:57:35 -06:00
Family string
Size float64 // as a text size, for instance 12 for a 12-point font
Weight TextWeight
Italic TextItalic
SmallCaps bool
Stretch TextStretch
// TODO gravity
}
2016-01-12 17:34:51 -06:00
// 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
2016-01-12 17:39:14 -06:00
// 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
2016-01-12 17:34:51 -06:00
// 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 . SmallCaps = frombool ( desc . SmallCaps )
d . Stretch = C . uiDrawTextStretch ( desc . Stretch )
// d.Gravity = C.uiDrawTextGravity(desc.Gravity)
d . Gravity = C . uiDrawTextGravitySouth
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
2016-01-12 17:41:49 -06:00
// TODO rewrite that first sentence
2016-01-12 17:34:51 -06:00
func ( f * Font ) Describe ( ) * FontDescriptor {
panic ( "TODO unimplemented" )
}
2016-01-13 16:57:23 -06:00
// 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
}
2016-01-09 19:57:35 -06:00
// TextLayout is the entry point for formatting a block of text to be
// drawn onto a DrawContext.
//
2016-01-12 17:34:51 -06:00
// 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
2016-01-09 19:57:35 -06:00
// 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.
2016-01-16 15:56:58 -06:00
//
// The block of text can either be a single line or multiple
// word-wrapped lines, each with a given maximum width.
2016-01-09 19:57:35 -06:00
type TextLayout struct {
l * C . uiDrawTextLayout
}
// NewTextLayout creates a new TextLayout.
2016-01-16 15:56:58 -06:00
// For details on the width parameter, see SetWidth.
func NewTextLayout ( text string , defaultFont * Font , width float64 ) * TextLayout {
2016-01-09 19:57:35 -06:00
l := new ( TextLayout )
2016-01-12 17:34:51 -06:00
ctext := C . CString ( text ) // freed by C.newTextLayout()
2016-01-16 15:56:58 -06:00
l . l = C . newTextLayout ( ctext , defaultFont . f , C . double ( width ) )
2016-01-09 19:57:35 -06:00
return l
}
// Free destroys a TextLayout. After calling Free the TextLayout
// cannot be used.
func ( l * TextLayout ) Free ( ) {
C . uiDrawFreeTextLayout ( l . l )
}
2016-01-16 15:56:58 -06:00
// 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.
2016-01-16 17:27:18 -06:00
//
// 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.
2016-01-16 15:56:58 -06:00
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
}
2016-01-09 19:57:35 -06:00
// 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 )
}