github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/framework/drawing.go (about)

     1  package framework
     2  
     3  import (
     4  	"image"
     5  	"image/color"
     6  
     7  	"github.com/gop9/olt/framework/command"
     8  	"github.com/gop9/olt/framework/font"
     9  	"github.com/gop9/olt/framework/label"
    10  	"github.com/gop9/olt/framework/rect"
    11  	nstyle "github.com/gop9/olt/framework/style"
    12  )
    13  
    14  func drawSymbol(out *command.Buffer, type_ label.SymbolType, content rect.Rect, background color.RGBA, foreground color.RGBA, border_width int, font font.Face) {
    15  	triangleSymbol := func(heading Heading) {
    16  		points := triangleFromDirection(content, border_width, border_width, heading)
    17  		out.FillTriangle(points[0], points[1], points[2], foreground)
    18  	}
    19  	switch type_ {
    20  	case label.SymbolX,
    21  		label.SymbolUnderscore,
    22  		label.SymbolPlus,
    23  		label.SymbolMinus:
    24  		var X string
    25  		switch type_ {
    26  		case label.SymbolX:
    27  			X = "x"
    28  		case label.SymbolUnderscore:
    29  			X = "_"
    30  		case label.SymbolPlus:
    31  			X = "+"
    32  		case label.SymbolMinus:
    33  			X = "-"
    34  		}
    35  
    36  		var text textWidget
    37  		text.Padding = image.Point{0, 0}
    38  		text.Background = background
    39  		text.Text = foreground
    40  		widgetText(out, content, X, &text, "CC", font)
    41  	case label.SymbolRect, label.SymbolRectFilled:
    42  		out.FillRect(content, 0, foreground)
    43  		if type_ == label.SymbolRectFilled {
    44  			out.FillRect(shrinkRect(content, border_width), 0, background)
    45  		}
    46  	case label.SymbolCircle, label.SymbolCircleFilled:
    47  		out.FillCircle(content, foreground)
    48  		if type_ == label.SymbolCircleFilled {
    49  			out.FillCircle(shrinkRect(content, 1), background)
    50  		}
    51  	case label.SymbolTriangleUp:
    52  		triangleSymbol(Up)
    53  	case label.SymbolTriangleDown:
    54  		triangleSymbol(Down)
    55  	case label.SymbolTriangleLeft:
    56  		triangleSymbol(Left)
    57  	case label.SymbolTriangleRight:
    58  		triangleSymbol(Right)
    59  	default:
    60  		fallthrough
    61  	case label.SymbolNone:
    62  		break
    63  	}
    64  }
    65  
    66  ///////////////////////////////////////////////////////////////////////////////////
    67  // WINOWS
    68  ///////////////////////////////////////////////////////////////////////////////////
    69  
    70  type drawableWindowHeader struct {
    71  	Header  rect.Rect
    72  	Label   rect.Rect
    73  	Hovered bool // titlebar is hovered
    74  	Focused bool // window has focus
    75  	Title   string
    76  
    77  	Dynamic       bool
    78  	HeaderActive  bool // should display titlebar
    79  	Bounds        rect.Rect
    80  	RowHeight     int
    81  	LayoutWidth   int
    82  	LayoutHeaderH int
    83  	Style         *nstyle.Window
    84  }
    85  
    86  func (dwh *drawableWindowHeader) Draw(z *nstyle.Style, out *command.Buffer) {
    87  	style := dwh.Style
    88  	if !dwh.Dynamic {
    89  		/* draw fixed window body */
    90  		body := dwh.Bounds
    91  		if dwh.HeaderActive {
    92  			body.Y += dwh.LayoutHeaderH - 1
    93  			body.H -= dwh.LayoutHeaderH
    94  		}
    95  
    96  		if style.FixedBackground.Type == nstyle.ItemImage {
    97  			out.DrawImage(body, style.FixedBackground.Data.Image)
    98  		} else {
    99  			out.FillRect(body, 0, style.FixedBackground.Data.Color)
   100  		}
   101  	} else {
   102  		/* draw dynamic window body */
   103  		out.FillRect(rect.Rect{dwh.Bounds.X, dwh.Bounds.Y, dwh.Bounds.W, dwh.RowHeight + style.Padding.Y}, 0, style.Background)
   104  	}
   105  
   106  	if dwh.HeaderActive {
   107  		var background *nstyle.Item
   108  		var text textWidget
   109  
   110  		/* select correct header background and text color */
   111  		switch {
   112  		case dwh.Focused:
   113  			background = &style.Header.Active
   114  			text.Text = style.Header.LabelActive
   115  		case dwh.Hovered:
   116  			background = &style.Header.Hover
   117  			text.Text = style.Header.LabelHover
   118  		default:
   119  			background = &style.Header.Normal
   120  			text.Text = style.Header.LabelNormal
   121  		}
   122  
   123  		/* draw header background */
   124  		if background.Type == nstyle.ItemImage {
   125  			text.Background = color.RGBA{0, 0, 0, 0}
   126  			out.DrawImage(dwh.Header, background.Data.Image)
   127  		} else {
   128  			text.Background = background.Data.Color
   129  			out.FillRect(dwh.Header, 0, background.Data.Color)
   130  		}
   131  
   132  		text.Padding = image.Point{0, 0}
   133  		widgetText(out, dwh.Label, dwh.Title, &text, "LC", z.Font)
   134  	}
   135  }
   136  
   137  type drawableWindowBody struct {
   138  	NoScrollbar bool
   139  	Bounds      rect.Rect
   140  	LayoutWidth int
   141  	Clip        rect.Rect
   142  	Style       *nstyle.Window
   143  }
   144  
   145  func (dwb *drawableWindowBody) Draw(z *nstyle.Style, out *command.Buffer) {
   146  
   147  	out.PushScissor(dwb.Clip)
   148  	out.Clip.X = dwb.Bounds.X
   149  	out.Clip.W = dwb.LayoutWidth
   150  	if !dwb.NoScrollbar {
   151  		out.Clip.W += dwb.Style.ScrollbarSize.X
   152  	}
   153  }
   154  
   155  type drawableScalerAndBorders struct {
   156  	DrawScaler bool
   157  	ScalerRect rect.Rect
   158  
   159  	DrawHeaderBorder bool
   160  	DrawBorders      bool
   161  	Bounds           rect.Rect
   162  	Border           int
   163  	HeaderH          int
   164  	BorderColor      color.RGBA
   165  	PaddingY         int
   166  	Style            *nstyle.Window
   167  }
   168  
   169  func (d *drawableScalerAndBorders) Draw(z *nstyle.Style, out *command.Buffer) {
   170  	style := d.Style
   171  	if d.DrawScaler {
   172  		/* draw scaler */
   173  		if style.Scaler.Type == nstyle.ItemImage {
   174  			out.DrawImage(d.ScalerRect, style.Scaler.Data.Image)
   175  		} else {
   176  			out.FillTriangle(image.Point{d.ScalerRect.X + d.ScalerRect.W, d.ScalerRect.Y}, d.ScalerRect.Max(), image.Point{d.ScalerRect.X, d.ScalerRect.Y + d.ScalerRect.H}, style.Scaler.Data.Color)
   177  		}
   178  	}
   179  
   180  	if d.DrawHeaderBorder {
   181  		out.StrokeLine(image.Point{d.Bounds.X + d.Border/2.0, d.Bounds.Y + d.HeaderH - d.Border}, image.Point{d.Bounds.X + d.Bounds.W - d.Border, d.Bounds.Y + d.HeaderH - d.Border}, d.Border, d.BorderColor)
   182  	}
   183  
   184  	if d.DrawBorders {
   185  		/* draw border top */
   186  		out.StrokeLine(image.Point{d.Bounds.X + d.Border/2.0, d.Bounds.Y + d.Border/2.0}, image.Point{d.Bounds.X + d.Bounds.W - d.Border, d.Bounds.Y + d.Border/2.0}, style.Border, d.BorderColor)
   187  
   188  		/* draw bottom border */
   189  		out.StrokeLine(image.Point{d.Bounds.X + d.Border/2.0, d.PaddingY - d.Border}, image.Point{d.Bounds.X + d.Bounds.W - d.Border, d.PaddingY - d.Border}, d.Border, d.BorderColor)
   190  
   191  		/* draw left border */
   192  		out.StrokeLine(image.Point{d.Bounds.X + d.Border/2.0, d.Bounds.Y + d.Border/2.0}, image.Point{d.Bounds.X + d.Border/2.0, d.PaddingY - d.Border}, d.Border, d.BorderColor)
   193  
   194  		/* draw right border */
   195  		out.StrokeLine(image.Point{d.Bounds.X + d.Bounds.W - d.Border, d.Bounds.Y + d.Border/2.0}, image.Point{d.Bounds.X + d.Bounds.W - d.Border, d.PaddingY - d.Border}, d.Border, d.BorderColor)
   196  	}
   197  
   198  }
   199  
   200  ///////////////////////////////////////////////////////////////////////////////////
   201  // TREE
   202  ///////////////////////////////////////////////////////////////////////////////////
   203  
   204  func drawTreeNode(win *Window, style *nstyle.Window, type_ TreeType, header rect.Rect, sym rect.Rect) rect.Rect {
   205  	z := &win.ctx.Style
   206  	out := &win.cmds
   207  
   208  	item_spacing := style.Spacing
   209  	panel_padding := style.Padding
   210  
   211  	if type_ == TreeTab {
   212  		var background *nstyle.Item = &z.Tab.Background
   213  		if background.Type == nstyle.ItemImage {
   214  			win.cmds.DrawImage(header, background.Data.Image)
   215  		} else {
   216  			out.FillRect(header, 0, z.Tab.BorderColor)
   217  			out.FillRect(shrinkRect(header, z.Tab.Border), z.Tab.Rounding, background.Data.Color)
   218  		}
   219  	}
   220  
   221  	/* draw node label */
   222  	var lblrect rect.Rect
   223  	header.W = max(header.W, sym.W+item_spacing.Y+panel_padding.X)
   224  	lblrect.X = sym.X + sym.W + item_spacing.X + 2*z.Tab.Spacing.X
   225  	lblrect.Y = sym.Y
   226  	lblrect.W = header.W - (sym.W + 2*z.Tab.Spacing.X + item_spacing.Y + panel_padding.X)
   227  	lblrect.H = FontHeight(z.Font)
   228  
   229  	return lblrect
   230  }
   231  
   232  ///////////////////////////////////////////////////////////////////////////////////
   233  // BUTTON
   234  ///////////////////////////////////////////////////////////////////////////////////
   235  
   236  func drawButton(out *command.Buffer, bounds rect.Rect, state nstyle.WidgetStates, style *nstyle.Button) *nstyle.Item {
   237  	var background *nstyle.Item
   238  	if state&nstyle.WidgetStateHovered != 0 {
   239  		background = &style.Hover
   240  	} else if state&nstyle.WidgetStateActive != 0 {
   241  		background = &style.Active
   242  	} else {
   243  		background = &style.Normal
   244  	}
   245  
   246  	if background.Type == nstyle.ItemImage {
   247  		out.DrawImage(bounds, background.Data.Image)
   248  	} else {
   249  		out.FillRect(bounds, style.Rounding, style.BorderColor)
   250  		out.FillRect(shrinkRect(bounds, style.Border), style.Rounding, background.Data.Color)
   251  	}
   252  
   253  	return background
   254  }
   255  
   256  func drawTextButton(win *Window, bounds rect.Rect, content rect.Rect, state nstyle.WidgetStates, style *nstyle.Button, txt string, align label.Align) {
   257  	out := &win.cmds
   258  	font := win.ctx.Style.Font
   259  
   260  	if style.DrawBegin != nil {
   261  		style.DrawBegin(out)
   262  	}
   263  	if style.DrawEnd != nil {
   264  		defer style.DrawEnd(out)
   265  	}
   266  
   267  	if style.Draw.ButtonText != nil {
   268  		style.Draw.ButtonText(out, bounds.Rectangle(), content.Rectangle(), state, style, txt, align, font)
   269  		return
   270  	}
   271  
   272  	background := drawButton(out, bounds, state, style)
   273  
   274  	/* select correct colors/images */
   275  	var text textWidget
   276  	if background.Type == nstyle.ItemColor {
   277  		text.Background = background.Data.Color
   278  	} else {
   279  		text.Background = style.TextBackground
   280  	}
   281  	if state&nstyle.WidgetStateHovered != 0 {
   282  		text.Text = style.TextHover
   283  	} else if state&nstyle.WidgetStateActive != 0 {
   284  		text.Text = style.TextActive
   285  	} else {
   286  		text.Text = style.TextNormal
   287  	}
   288  
   289  	widgetText(out, content, txt, &text, align, font)
   290  
   291  }
   292  
   293  func drawSymbolButton(win *Window, bounds rect.Rect, content rect.Rect, state nstyle.WidgetStates, style *nstyle.Button, symbol label.SymbolType) {
   294  	out := &win.cmds
   295  	font := win.ctx.Style.Font
   296  
   297  	if style.DrawBegin != nil {
   298  		style.DrawBegin(out)
   299  	}
   300  	if style.DrawEnd != nil {
   301  		defer style.DrawEnd(out)
   302  	}
   303  	if style.Draw.ButtonSymbol != nil {
   304  		style.Draw.ButtonSymbol(out, bounds.Rectangle(), content.Rectangle(), state, style, symbol, font)
   305  		return
   306  	}
   307  
   308  	background := drawButton(out, bounds, state, style)
   309  	var bg color.RGBA
   310  	if background.Type == nstyle.ItemColor {
   311  		bg = background.Data.Color
   312  	} else {
   313  		bg = style.TextBackground
   314  	}
   315  
   316  	var sym color.RGBA
   317  	if state&nstyle.WidgetStateHovered != 0 {
   318  		sym = style.TextHover
   319  	} else if state&nstyle.WidgetStateActive != 0 {
   320  		sym = style.TextActive
   321  	} else {
   322  		sym = style.TextNormal
   323  	}
   324  	drawSymbol(out, symbol, content, bg, sym, style.SymbolBorderWidth, font)
   325  }
   326  
   327  func drawImageButton(win *Window, bounds rect.Rect, content rect.Rect, state nstyle.WidgetStates, style *nstyle.Button, img *image.RGBA) {
   328  	out := &win.cmds
   329  	if style.DrawBegin != nil {
   330  		style.DrawBegin(out)
   331  	}
   332  	if style.DrawEnd != nil {
   333  		defer style.DrawEnd(out)
   334  	}
   335  	if style.Draw.ButtonImage != nil {
   336  		style.Draw.ButtonImage(out, bounds.Rectangle(), content.Rectangle(), state, style, img)
   337  		return
   338  	}
   339  	drawButton(out, bounds, state, style)
   340  	out.DrawImage(content, img)
   341  }
   342  
   343  func drawTextSymbolButton(win *Window, bounds, labelrect, symbolrect rect.Rect, state nstyle.WidgetStates, style *nstyle.Button, str string, symbol label.SymbolType) {
   344  	out := &win.cmds
   345  	font := win.ctx.Style.Font
   346  
   347  	if style.DrawBegin != nil {
   348  		style.DrawBegin(out)
   349  	}
   350  	if style.DrawEnd != nil {
   351  		defer style.DrawEnd(out)
   352  	}
   353  	if style.Draw.ButtonTextSymbol != nil {
   354  		style.Draw.ButtonTextSymbol(out, bounds.Rectangle(), labelrect.Rectangle(), symbolrect.Rectangle(), state, style, str, symbol, font)
   355  		return
   356  	}
   357  
   358  	/* select correct background colors/images */
   359  	background := drawButton(out, bounds, state, style)
   360  
   361  	var text textWidget
   362  	if background.Type == nstyle.ItemColor {
   363  		text.Background = background.Data.Color
   364  	} else {
   365  		text.Background = style.TextBackground
   366  	}
   367  
   368  	/* select correct text colors */
   369  	var sym color.RGBA
   370  	if state&nstyle.WidgetStateHovered != 0 {
   371  		sym = style.TextHover
   372  		text.Text = style.TextHover
   373  	} else if state&nstyle.WidgetStateActive != 0 {
   374  		sym = style.TextActive
   375  		text.Text = style.TextActive
   376  	} else {
   377  		sym = style.TextNormal
   378  		text.Text = style.TextNormal
   379  	}
   380  
   381  	text.Padding = image.Point{0, 0}
   382  	drawSymbol(out, symbol, symbolrect, style.TextBackground, sym, 0, font)
   383  	widgetText(out, labelrect, str, &text, "CC", font)
   384  }
   385  
   386  func drawTextImageButton(win *Window, bounds, labelrect, imgrect rect.Rect, state nstyle.WidgetStates, style *nstyle.Button, str string, img *image.RGBA) {
   387  	out := &win.cmds
   388  	font := win.ctx.Style.Font
   389  
   390  	if style.DrawBegin != nil {
   391  		style.DrawBegin(out)
   392  	}
   393  	if style.DrawEnd != nil {
   394  		defer style.DrawEnd(out)
   395  	}
   396  	if style.Draw.ButtonTextImage != nil {
   397  		style.Draw.ButtonTextImage(out, bounds.Rectangle(), labelrect.Rectangle(), imgrect.Rectangle(), state, style, str, font, img)
   398  		return
   399  	}
   400  
   401  	background := drawButton(out, bounds, state, style)
   402  
   403  	/* select correct colors */
   404  	var text textWidget
   405  	if background.Type == nstyle.ItemColor {
   406  		text.Background = background.Data.Color
   407  	} else {
   408  		text.Background = style.TextBackground
   409  	}
   410  	if state&nstyle.WidgetStateHovered != 0 {
   411  		text.Text = style.TextHover
   412  	} else if state&nstyle.WidgetStateActive != 0 {
   413  		text.Text = style.TextActive
   414  	} else {
   415  		text.Text = style.TextNormal
   416  	}
   417  
   418  	text.Padding = image.Point{0, 0}
   419  	widgetText(out, labelrect, str, &text, "CC", font)
   420  	out.DrawImage(imgrect, img)
   421  }
   422  
   423  ///////////////////////////////////////////////////////////////////////////////////
   424  // SELECTABLE
   425  ///////////////////////////////////////////////////////////////////////////////////
   426  
   427  func drawSelectable(win *Window, state nstyle.WidgetStates, style *nstyle.Selectable, active bool, bounds rect.Rect, str string, align label.Align) {
   428  	out := &win.cmds
   429  	font := win.ctx.Style.Font
   430  
   431  	if style.DrawBegin != nil {
   432  		style.DrawBegin(out)
   433  	}
   434  	if style.DrawEnd != nil {
   435  		defer style.DrawEnd(out)
   436  	}
   437  	if style.Draw != nil {
   438  		style.Draw(out, state, style, active, bounds.Rectangle(), str, align, font)
   439  		return
   440  	}
   441  
   442  	var background *nstyle.Item
   443  	var text textWidget
   444  	text.Padding = style.Padding
   445  
   446  	/* select correct colors/images */
   447  	if !active {
   448  		if state&nstyle.WidgetStateActive != 0 {
   449  			background = &style.Pressed
   450  			text.Text = style.TextPressed
   451  		} else if state&nstyle.WidgetStateHovered != 0 {
   452  			background = &style.Hover
   453  			text.Text = style.TextHover
   454  		} else {
   455  			background = &style.Normal
   456  			text.Text = style.TextNormal
   457  		}
   458  	} else {
   459  		if state&nstyle.WidgetStateActive != 0 {
   460  			background = &style.PressedActive
   461  			text.Text = style.TextPressedActive
   462  		} else if state&nstyle.WidgetStateHovered != 0 {
   463  			background = &style.HoverActive
   464  			text.Text = style.TextHoverActive
   465  		} else {
   466  			background = &style.NormalActive
   467  			text.Text = style.TextNormalActive
   468  		}
   469  	}
   470  
   471  	/* draw selectable background and text */
   472  	if background.Type == nstyle.ItemImage {
   473  		out.DrawImage(bounds, background.Data.Image)
   474  		text.Background = color.RGBA{0, 0, 0, 0}
   475  	} else {
   476  		out.FillRect(bounds, style.Rounding, background.Data.Color)
   477  		text.Background = background.Data.Color
   478  	}
   479  
   480  	widgetText(out, bounds, str, &text, align, font)
   481  }
   482  
   483  ///////////////////////////////////////////////////////////////////////////////////
   484  // SCROLLBARS
   485  ///////////////////////////////////////////////////////////////////////////////////
   486  
   487  func drawScrollbar(win *Window, state nstyle.WidgetStates, style *nstyle.Scrollbar, bounds, scroll rect.Rect) {
   488  	out := &win.cmds
   489  	if style.DrawBegin != nil {
   490  		style.DrawBegin(out)
   491  	}
   492  	if style.DrawEnd != nil {
   493  		defer style.DrawEnd(out)
   494  	}
   495  	if style.Draw != nil {
   496  		style.Draw(out, state, style, bounds.Rectangle(), scroll.Rectangle())
   497  		return
   498  	}
   499  
   500  	/* select correct colors/images to draw */
   501  	var background *nstyle.Item
   502  	var cursorstyle *nstyle.Item
   503  	if state&nstyle.WidgetStateActive != 0 {
   504  		background = &style.Active
   505  		cursorstyle = &style.CursorActive
   506  	} else if state&nstyle.WidgetStateHovered != 0 {
   507  		background = &style.Hover
   508  		cursorstyle = &style.CursorHover
   509  	} else {
   510  		background = &style.Normal
   511  		cursorstyle = &style.CursorNormal
   512  	}
   513  
   514  	/* draw background */
   515  	if background.Type == nstyle.ItemColor {
   516  		out.FillRect(bounds, style.Rounding, style.BorderColor)
   517  		out.FillRect(shrinkRect(bounds, style.Border), style.Rounding, background.Data.Color)
   518  	} else {
   519  		out.DrawImage(bounds, background.Data.Image)
   520  	}
   521  
   522  	/* draw cursor */
   523  	if cursorstyle.Type == nstyle.ItemImage {
   524  		out.DrawImage(scroll, cursorstyle.Data.Image)
   525  	} else {
   526  		out.FillRect(scroll, style.Rounding, cursorstyle.Data.Color)
   527  	}
   528  }
   529  
   530  ///////////////////////////////////////////////////////////////////////////////////
   531  // TOGGLE BOXES
   532  ///////////////////////////////////////////////////////////////////////////////////
   533  
   534  func drawTogglebox(win *Window, type_ toggleType, state nstyle.WidgetStates, style *nstyle.Toggle, active bool, labelrect, select_, cursor rect.Rect, str string) {
   535  	out := &win.cmds
   536  	font := win.ctx.Style.Font
   537  
   538  	if style.DrawBegin != nil {
   539  		style.DrawBegin(out)
   540  	}
   541  	if style.DrawEnd != nil {
   542  		defer style.DrawEnd(out)
   543  	}
   544  	switch type_ {
   545  	case toggleCheck:
   546  		if style.Draw.Checkbox != nil {
   547  			style.Draw.Checkbox(out, state, style, active, labelrect.Rectangle(), select_.Rectangle(), cursor.Rectangle(), str, font)
   548  			return
   549  		}
   550  	default:
   551  		if style.Draw.Radio != nil {
   552  			style.Draw.Radio(out, state, style, active, labelrect.Rectangle(), select_.Rectangle(), cursor.Rectangle(), str, font)
   553  			return
   554  		}
   555  	}
   556  
   557  	/* select correct colors/images */
   558  	var background *nstyle.Item
   559  	var cursorstyle *nstyle.Item
   560  	var text textWidget
   561  	if state&nstyle.WidgetStateHovered != 0 {
   562  		background = &style.Hover
   563  		cursorstyle = &style.CursorHover
   564  		text.Text = style.TextHover
   565  	} else if state&nstyle.WidgetStateActive != 0 {
   566  		background = &style.Hover
   567  		cursorstyle = &style.CursorHover
   568  		text.Text = style.TextActive
   569  	} else {
   570  		background = &style.Normal
   571  		cursorstyle = &style.CursorNormal
   572  		text.Text = style.TextNormal
   573  	}
   574  
   575  	/* draw background and cursor */
   576  	if background.Type == nstyle.ItemImage {
   577  		out.DrawImage(select_, background.Data.Image)
   578  	} else {
   579  		switch type_ {
   580  		case toggleCheck:
   581  			out.FillRect(select_, 0, background.Data.Color)
   582  		default:
   583  			out.FillCircle(select_, background.Data.Color)
   584  		}
   585  	}
   586  	if active {
   587  		if cursorstyle.Type == nstyle.ItemImage {
   588  			out.DrawImage(cursor, cursorstyle.Data.Image)
   589  		} else {
   590  			switch type_ {
   591  			case toggleCheck:
   592  				out.FillRect(cursor, 0, cursorstyle.Data.Color)
   593  			default:
   594  				out.FillCircle(cursor, cursorstyle.Data.Color)
   595  			}
   596  		}
   597  	}
   598  
   599  	text.Padding.X = 0
   600  	text.Padding.Y = 0
   601  	text.Background = style.TextBackground
   602  	widgetText(out, labelrect, str, &text, "LC", font)
   603  }
   604  
   605  ///////////////////////////////////////////////////////////////////////////////////
   606  // PROGRESS BAR
   607  ///////////////////////////////////////////////////////////////////////////////////
   608  
   609  func drawProgress(win *Window, state nstyle.WidgetStates, style *nstyle.Progress, bounds, scursor rect.Rect, value, maxval int) {
   610  	out := &win.cmds
   611  	if style.DrawBegin != nil {
   612  		style.DrawBegin(out)
   613  	}
   614  	if style.DrawEnd != nil {
   615  		defer style.DrawEnd(out)
   616  	}
   617  
   618  	if style.Draw != nil {
   619  		style.Draw(out, state, style, bounds.Rectangle(), scursor.Rectangle(), value, maxval)
   620  		return
   621  	}
   622  
   623  	var background *nstyle.Item
   624  	var cursor *nstyle.Item
   625  
   626  	/* select correct colors/images to draw */
   627  	if state&nstyle.WidgetStateActive != 0 {
   628  		background = &style.Active
   629  		cursor = &style.CursorActive
   630  	} else if state&nstyle.WidgetStateHovered != 0 {
   631  		background = &style.Hover
   632  		cursor = &style.CursorHover
   633  	} else {
   634  		background = &style.Normal
   635  		cursor = &style.CursorNormal
   636  	}
   637  
   638  	/* draw background */
   639  	if background.Type == nstyle.ItemImage {
   640  		out.DrawImage(bounds, background.Data.Image)
   641  	} else {
   642  		out.FillRect(bounds, style.Rounding, background.Data.Color)
   643  	}
   644  
   645  	/* draw cursor */
   646  	if cursor.Type == nstyle.ItemImage {
   647  		out.DrawImage(scursor, cursor.Data.Image)
   648  	} else {
   649  		out.FillRect(scursor, style.Rounding, cursor.Data.Color)
   650  	}
   651  }
   652  
   653  ///////////////////////////////////////////////////////////////////////////////////
   654  // SLIDER
   655  ///////////////////////////////////////////////////////////////////////////////////
   656  
   657  func drawSlider(win *Window, state nstyle.WidgetStates, style *nstyle.Slider, bounds, virtual_cursor rect.Rect, minval, value, maxval float64) {
   658  	out := &win.cmds
   659  	if style.DrawBegin != nil {
   660  		style.DrawBegin(out)
   661  	}
   662  	if style.DrawEnd != nil {
   663  		defer style.DrawEnd(out)
   664  	}
   665  	if style.Draw != nil {
   666  		style.Draw(out, state, style, bounds.Rectangle(), virtual_cursor.Rectangle(), minval, value, maxval)
   667  		return
   668  	}
   669  
   670  	var fill rect.Rect
   671  	var bar rect.Rect
   672  	var scursor rect.Rect
   673  	var background *nstyle.Item
   674  	var bar_color color.RGBA
   675  	var cursor *nstyle.Item
   676  
   677  	/* select correct slider images/colors */
   678  	if state&nstyle.WidgetStateActive != 0 {
   679  		background = &style.Active
   680  		bar_color = style.BarActive
   681  		cursor = &style.CursorActive
   682  	} else if state&nstyle.WidgetStateHovered != 0 {
   683  		background = &style.Hover
   684  		bar_color = style.BarHover
   685  		cursor = &style.CursorHover
   686  	} else {
   687  		background = &style.Normal
   688  		bar_color = style.BarNormal
   689  		cursor = &style.CursorNormal
   690  	}
   691  
   692  	/* calculate slider background bar */
   693  	bar.X = bounds.X
   694  	bar.Y = (bounds.Y + virtual_cursor.H/2) - virtual_cursor.H/8
   695  	bar.W = bounds.W
   696  	bar.H = bounds.H / 6
   697  
   698  	/* resize virtual cursor to given size */
   699  	scursor.H = style.CursorSize.Y
   700  	scursor.W = style.CursorSize.X
   701  	scursor.Y = (bar.Y + bar.H/2.0) - scursor.H/2.0
   702  	scursor.X = virtual_cursor.X - (virtual_cursor.W / 2)
   703  
   704  	/* filled background bar style */
   705  	fill.W = (scursor.X + (scursor.W / 2.0)) - bar.X
   706  
   707  	fill.X = bar.X
   708  	fill.Y = bar.Y
   709  	fill.H = bar.H
   710  
   711  	/* draw background */
   712  	if background.Type == nstyle.ItemImage {
   713  		out.DrawImage(bounds, background.Data.Image)
   714  	} else {
   715  		out.FillRect(bounds, style.Rounding, style.BorderColor)
   716  		out.FillRect(shrinkRect(bounds, style.Border), style.Rounding, background.Data.Color)
   717  	}
   718  
   719  	/* draw slider bar */
   720  	out.FillRect(bar, style.Rounding, bar_color)
   721  
   722  	out.FillRect(fill, style.Rounding, style.BarFilled)
   723  
   724  	/* draw cursor */
   725  	if cursor.Type == nstyle.ItemImage {
   726  		out.DrawImage(scursor, cursor.Data.Image)
   727  	} else {
   728  		out.FillCircle(scursor, cursor.Data.Color)
   729  	}
   730  }
   731  
   732  ///////////////////////////////////////////////////////////////////////////////////
   733  // PROPERTY
   734  ///////////////////////////////////////////////////////////////////////////////////
   735  
   736  func drawProperty(win *Window, style *nstyle.Property, bounds, labelrect rect.Rect, ws nstyle.WidgetStates, name string) {
   737  	out := &win.cmds
   738  	font := win.ctx.Style.Font
   739  
   740  	if style.DrawBegin != nil {
   741  		style.DrawBegin(out)
   742  	}
   743  	if style.DrawEnd != nil {
   744  		defer style.DrawEnd(out)
   745  	}
   746  	if style.Draw != nil {
   747  		style.Draw(out, style, bounds.Rectangle(), labelrect.Rectangle(), ws, name, font)
   748  		return
   749  	}
   750  
   751  	var text textWidget
   752  	var background *nstyle.Item
   753  
   754  	// select correct background and text color
   755  	if ws&nstyle.WidgetStateActive != 0 {
   756  		background = &style.Active
   757  		text.Text = style.LabelActive
   758  	} else if ws&nstyle.WidgetStateHovered != 0 {
   759  		background = &style.Hover
   760  		text.Text = style.LabelHover
   761  	} else {
   762  		background = &style.Normal
   763  		text.Text = style.LabelNormal
   764  	}
   765  
   766  	// draw background
   767  	if background.Type == nstyle.ItemImage {
   768  		out.DrawImage(bounds, background.Data.Image)
   769  		text.Background = color.RGBA{0, 0, 0, 0}
   770  	} else {
   771  		text.Background = background.Data.Color
   772  		out.FillRect(bounds, style.Rounding, style.BorderColor)
   773  		out.FillRect(shrinkRect(bounds, style.Border), style.Rounding, background.Data.Color)
   774  	}
   775  
   776  	// draw label
   777  	widgetText(out, labelrect, name, &text, "CC", font)
   778  }
   779  
   780  ///////////////////////////////////////////////////////////////////////////////////
   781  // COMBO-BOX
   782  ///////////////////////////////////////////////////////////////////////////////////
   783  
   784  func drawComboColor(win *Window, state nstyle.WidgetStates, header rect.Rect, is_active bool, color color.RGBA) {
   785  	style := &win.ctx.Style
   786  	out := &win.cmds
   787  	/* draw combo box header background and border */
   788  	var background *nstyle.Item
   789  	if state&nstyle.WidgetStateActive != 0 {
   790  		background = &style.Combo.Active
   791  	} else if state&nstyle.WidgetStateHovered != 0 {
   792  		background = &style.Combo.Hover
   793  	} else {
   794  		background = &style.Combo.Normal
   795  	}
   796  
   797  	if background.Type == nstyle.ItemImage {
   798  		out.DrawImage(header, background.Data.Image)
   799  	} else {
   800  		out.FillRect(header, 0, style.Combo.BorderColor)
   801  		out.FillRect(shrinkRect(header, 1), 0, background.Data.Color)
   802  	}
   803  	{
   804  		var content rect.Rect
   805  		var button rect.Rect
   806  		var bounds rect.Rect
   807  		var sym label.SymbolType
   808  		if state&nstyle.WidgetStateHovered != 0 {
   809  			sym = style.Combo.SymHover
   810  		} else if is_active {
   811  			sym = style.Combo.SymActive
   812  		} else {
   813  			sym = style.Combo.SymNormal
   814  		}
   815  
   816  		/* calculate button */
   817  		button.W = header.H - 2*style.Combo.ButtonPadding.Y
   818  
   819  		button.X = (header.X + header.W - header.H) - style.Combo.ButtonPadding.X
   820  		button.Y = header.Y + style.Combo.ButtonPadding.Y
   821  		button.H = button.W
   822  
   823  		content.X = button.X + style.Combo.Button.Padding.X
   824  		content.Y = button.Y + style.Combo.Button.Padding.Y
   825  		content.W = button.W - 2*style.Combo.Button.Padding.X
   826  		content.H = button.H - 2*style.Combo.Button.Padding.Y
   827  
   828  		/* draw color */
   829  		bounds.H = header.H - 4*style.Combo.ContentPadding.Y
   830  
   831  		bounds.Y = header.Y + 2*style.Combo.ContentPadding.Y
   832  		bounds.X = header.X + 2*style.Combo.ContentPadding.X
   833  		bounds.W = (button.X - (style.Combo.ContentPadding.X + style.Combo.Spacing.X)) - bounds.X
   834  		out.FillRect(bounds, 0, color)
   835  
   836  		/* draw open/close button */
   837  		drawSymbolButton(win, button, content, state, &style.Combo.Button, sym)
   838  	}
   839  }
   840  
   841  func drawComboSymbol(win *Window, state nstyle.WidgetStates, header rect.Rect, is_active bool, symbol label.SymbolType) {
   842  	style := &win.ctx.Style
   843  	out := &win.cmds
   844  	var background *nstyle.Item
   845  	var sym_background color.RGBA
   846  	var symbol_color color.RGBA
   847  
   848  	/* draw combo box header background and border */
   849  	if state&nstyle.WidgetStateActive != 0 {
   850  		background = &style.Combo.Active
   851  		symbol_color = style.Combo.SymbolActive
   852  	} else if state&nstyle.WidgetStateHovered != 0 {
   853  		background = &style.Combo.Hover
   854  		symbol_color = style.Combo.SymbolHover
   855  	} else {
   856  		background = &style.Combo.Normal
   857  		symbol_color = style.Combo.SymbolHover
   858  	}
   859  
   860  	if background.Type == nstyle.ItemImage {
   861  		sym_background = color.RGBA{0, 0, 0, 0}
   862  		out.DrawImage(header, background.Data.Image)
   863  	} else {
   864  		sym_background = background.Data.Color
   865  		out.FillRect(header, 0, style.Combo.BorderColor)
   866  		out.FillRect(shrinkRect(header, 1), 0, background.Data.Color)
   867  	}
   868  	{
   869  		var bounds = rect.Rect{0, 0, 0, 0}
   870  		var content rect.Rect
   871  		var button rect.Rect
   872  		var sym label.SymbolType
   873  		if state&nstyle.WidgetStateHovered != 0 {
   874  			sym = style.Combo.SymHover
   875  		} else if is_active {
   876  			sym = style.Combo.SymActive
   877  		} else {
   878  			sym = style.Combo.SymNormal
   879  		}
   880  
   881  		/* calculate button */
   882  		button.W = header.H - 2*style.Combo.ButtonPadding.Y
   883  
   884  		button.X = (header.X + header.W - header.H) - style.Combo.ButtonPadding.Y
   885  		button.Y = header.Y + style.Combo.ButtonPadding.Y
   886  		button.H = button.W
   887  
   888  		content.X = button.X + style.Combo.Button.Padding.X
   889  		content.Y = button.Y + style.Combo.Button.Padding.Y
   890  		content.W = button.W - 2*style.Combo.Button.Padding.X
   891  		content.H = button.H - 2*style.Combo.Button.Padding.Y
   892  
   893  		/* draw symbol */
   894  		bounds.H = header.H - 2*style.Combo.ContentPadding.Y
   895  
   896  		bounds.Y = header.Y + style.Combo.ContentPadding.Y
   897  		bounds.X = header.X + style.Combo.ContentPadding.X
   898  		bounds.W = (button.X - style.Combo.ContentPadding.Y) - bounds.X
   899  		drawSymbol(out, symbol, bounds, sym_background, symbol_color, 1.0, style.Font)
   900  
   901  		/* draw open/close button */
   902  		drawSymbolButton(win, button, content, state, &style.Combo.Button, sym)
   903  	}
   904  }
   905  
   906  func drawComboSymbolText(win *Window, state nstyle.WidgetStates, header rect.Rect, is_active bool, symbol label.SymbolType, selected string) {
   907  	style := &win.ctx.Style
   908  	out := &win.cmds
   909  	var background *nstyle.Item
   910  	var symbol_color color.RGBA
   911  	var text textWidget
   912  
   913  	/* draw combo box header background and border */
   914  	if state&nstyle.WidgetStateActive != 0 {
   915  		background = &style.Combo.Active
   916  		symbol_color = style.Combo.SymbolActive
   917  		text.Text = style.Combo.LabelActive
   918  	} else if state&nstyle.WidgetStateHovered != 0 {
   919  		background = &style.Combo.Hover
   920  		symbol_color = style.Combo.SymbolHover
   921  		text.Text = style.Combo.LabelHover
   922  	} else {
   923  		background = &style.Combo.Normal
   924  		symbol_color = style.Combo.SymbolNormal
   925  		text.Text = style.Combo.LabelNormal
   926  	}
   927  
   928  	if background.Type == nstyle.ItemImage {
   929  		text.Background = color.RGBA{0, 0, 0, 0}
   930  		out.DrawImage(header, background.Data.Image)
   931  	} else {
   932  		text.Background = background.Data.Color
   933  		out.FillRect(header, 0, style.Combo.BorderColor)
   934  		out.FillRect(shrinkRect(header, 1), 0, background.Data.Color)
   935  	}
   936  	{
   937  		var content rect.Rect
   938  		var button rect.Rect
   939  		var imrect rect.Rect
   940  		var sym label.SymbolType
   941  		if state&nstyle.WidgetStateHovered != 0 {
   942  			sym = style.Combo.SymHover
   943  		} else if is_active {
   944  			sym = style.Combo.SymActive
   945  		} else {
   946  			sym = style.Combo.SymNormal
   947  		}
   948  
   949  		/* calculate button */
   950  		button.W = header.H - 2*style.Combo.ButtonPadding.Y
   951  
   952  		button.X = (header.X + header.W - header.H) - style.Combo.ButtonPadding.X
   953  		button.Y = header.Y + style.Combo.ButtonPadding.Y
   954  		button.H = button.W
   955  
   956  		content.X = button.X + style.Combo.Button.Padding.X
   957  		content.Y = button.Y + style.Combo.Button.Padding.Y
   958  		content.W = button.W - 2*style.Combo.Button.Padding.X
   959  		content.H = button.H - 2*style.Combo.Button.Padding.Y
   960  		drawSymbolButton(win, button, content, state, &style.Combo.Button, sym)
   961  
   962  		/* draw symbol */
   963  		imrect.X = header.X + style.Combo.ContentPadding.X
   964  
   965  		imrect.Y = header.Y + style.Combo.ContentPadding.Y
   966  		imrect.H = header.H - 2*style.Combo.ContentPadding.Y
   967  		imrect.W = imrect.H
   968  		drawSymbol(out, symbol, imrect, text.Background, symbol_color, 1.0, style.Font)
   969  
   970  		/* draw label */
   971  		text.Padding = image.Point{0, 0}
   972  
   973  		var lblrect rect.Rect
   974  		lblrect.X = imrect.X + imrect.W + style.Combo.Spacing.X + style.Combo.ContentPadding.X
   975  		lblrect.Y = header.Y + style.Combo.ContentPadding.Y
   976  		lblrect.W = (button.X - style.Combo.ContentPadding.X) - lblrect.X
   977  		lblrect.H = header.H - 2*style.Combo.ContentPadding.Y
   978  		widgetText(out, lblrect, selected, &text, "LC", style.Font)
   979  	}
   980  }
   981  
   982  func drawComboImage(win *Window, state nstyle.WidgetStates, header rect.Rect, is_active bool, img *image.RGBA) {
   983  	style := &win.ctx.Style
   984  	out := &win.cmds
   985  	var background *nstyle.Item
   986  
   987  	/* draw combo box header background and border */
   988  	if state&nstyle.WidgetStateActive != 0 {
   989  		background = &style.Combo.Active
   990  	} else if state&nstyle.WidgetStateHovered != 0 {
   991  		background = &style.Combo.Hover
   992  	} else {
   993  		background = &style.Combo.Normal
   994  	}
   995  
   996  	if background.Type == nstyle.ItemImage {
   997  		out.DrawImage(header, background.Data.Image)
   998  	} else {
   999  		out.FillRect(header, 0, style.Combo.BorderColor)
  1000  		out.FillRect(shrinkRect(header, 1), 0, background.Data.Color)
  1001  	}
  1002  	{
  1003  		var bounds = rect.Rect{0, 0, 0, 0}
  1004  		var content rect.Rect
  1005  		var button rect.Rect
  1006  		var sym label.SymbolType
  1007  		if state&nstyle.WidgetStateHovered != 0 {
  1008  			sym = style.Combo.SymHover
  1009  		} else if is_active {
  1010  			sym = style.Combo.SymActive
  1011  		} else {
  1012  			sym = style.Combo.SymNormal
  1013  		}
  1014  
  1015  		/* calculate button */
  1016  		button.W = header.H - 2*style.Combo.ButtonPadding.Y
  1017  		button.X = (header.X + header.W - header.H) - style.Combo.ButtonPadding.Y
  1018  		button.Y = header.Y + style.Combo.ButtonPadding.Y
  1019  		button.H = button.W
  1020  
  1021  		content.X = button.X + style.Combo.Button.Padding.X
  1022  		content.Y = button.Y + style.Combo.Button.Padding.Y
  1023  		content.W = button.W - 2*style.Combo.Button.Padding.X
  1024  		content.H = button.H - 2*style.Combo.Button.Padding.Y
  1025  
  1026  		/* draw image */
  1027  		bounds.H = header.H - 2*style.Combo.ContentPadding.Y
  1028  		bounds.Y = header.Y + style.Combo.ContentPadding.Y
  1029  		bounds.X = header.X + style.Combo.ContentPadding.X
  1030  		bounds.W = (button.X - style.Combo.ContentPadding.Y) - bounds.X
  1031  		out.DrawImage(bounds, img)
  1032  
  1033  		/* draw open/close button */
  1034  		drawSymbolButton(win, button, content, state, &style.Combo.Button, sym)
  1035  	}
  1036  }
  1037  
  1038  func drawComboImageText(win *Window, state nstyle.WidgetStates, header rect.Rect, is_active bool, selected string, img *image.RGBA) {
  1039  	style := &win.ctx.Style
  1040  	out := &win.cmds
  1041  	var background *nstyle.Item
  1042  	var text textWidget
  1043  
  1044  	/* draw combo box header background and border */
  1045  	if state&nstyle.WidgetStateActive != 0 {
  1046  		background = &style.Combo.Active
  1047  		text.Text = style.Combo.LabelActive
  1048  	} else if state&nstyle.WidgetStateHovered != 0 {
  1049  		background = &style.Combo.Hover
  1050  		text.Text = style.Combo.LabelHover
  1051  	} else {
  1052  		background = &style.Combo.Normal
  1053  		text.Text = style.Combo.LabelNormal
  1054  	}
  1055  
  1056  	if background.Type == nstyle.ItemImage {
  1057  		text.Background = color.RGBA{0, 0, 0, 0}
  1058  		out.DrawImage(header, background.Data.Image)
  1059  	} else {
  1060  		text.Background = background.Data.Color
  1061  		out.FillRect(header, 0, style.Combo.BorderColor)
  1062  		out.FillRect(shrinkRect(header, 1), 0, background.Data.Color)
  1063  	}
  1064  	{
  1065  		var content rect.Rect
  1066  		var button rect.Rect
  1067  		var imrect rect.Rect
  1068  		var sym label.SymbolType
  1069  		if state&nstyle.WidgetStateHovered != 0 {
  1070  			sym = style.Combo.SymHover
  1071  		} else if is_active {
  1072  			sym = style.Combo.SymActive
  1073  		} else {
  1074  			sym = style.Combo.SymNormal
  1075  		}
  1076  
  1077  		/* calculate button */
  1078  		button.W = header.H - 2*style.Combo.ButtonPadding.Y
  1079  
  1080  		button.X = (header.X + header.W - header.H) - style.Combo.ButtonPadding.X
  1081  		button.Y = header.Y + style.Combo.ButtonPadding.Y
  1082  		button.H = button.W
  1083  
  1084  		content.X = button.X + style.Combo.Button.Padding.X
  1085  		content.Y = button.Y + style.Combo.Button.Padding.Y
  1086  		content.W = button.W - 2*style.Combo.Button.Padding.X
  1087  		content.H = button.H - 2*style.Combo.Button.Padding.Y
  1088  		drawSymbolButton(win, button, content, state, &style.Combo.Button, sym)
  1089  
  1090  		/* draw image */
  1091  		imrect.X = header.X + style.Combo.ContentPadding.X
  1092  		imrect.Y = header.Y + style.Combo.ContentPadding.Y
  1093  		imrect.H = header.H - 2*style.Combo.ContentPadding.Y
  1094  		imrect.W = imrect.H
  1095  		out.DrawImage(imrect, img)
  1096  
  1097  		/* draw label */
  1098  		text.Padding = image.Point{0, 0}
  1099  
  1100  		var lblrect rect.Rect
  1101  		lblrect.X = imrect.X + imrect.W + style.Combo.Spacing.X + style.Combo.ContentPadding.X
  1102  		lblrect.Y = header.Y + style.Combo.ContentPadding.Y
  1103  		lblrect.W = (button.X - style.Combo.ContentPadding.X) - lblrect.X
  1104  		lblrect.H = header.H - 2*style.Combo.ContentPadding.Y
  1105  		widgetText(out, lblrect, selected, &text, "LC", style.Font)
  1106  	}
  1107  }
  1108  
  1109  func drawComboText(win *Window, state nstyle.WidgetStates, header rect.Rect, is_active bool, selected string) {
  1110  	style := &win.ctx.Style
  1111  	out := &win.cmds
  1112  	/* draw combo box header background and border */
  1113  	var background *nstyle.Item
  1114  	var text textWidget
  1115  	if state&nstyle.WidgetStateActive != 0 {
  1116  		background = &style.Combo.Active
  1117  		text.Text = style.Combo.LabelActive
  1118  	} else if state&nstyle.WidgetStateHovered != 0 {
  1119  		background = &style.Combo.Hover
  1120  		text.Text = style.Combo.LabelHover
  1121  	} else {
  1122  		background = &style.Combo.Normal
  1123  		text.Text = style.Combo.LabelNormal
  1124  	}
  1125  
  1126  	if background.Type == nstyle.ItemImage {
  1127  		text.Background = color.RGBA{0, 0, 0, 0}
  1128  		out.DrawImage(header, background.Data.Image)
  1129  	} else {
  1130  		text.Background = background.Data.Color
  1131  		out.FillRect(header, style.Combo.Rounding, style.Combo.BorderColor)
  1132  		out.FillRect(shrinkRect(header, 1), style.Combo.Rounding, background.Data.Color)
  1133  	}
  1134  
  1135  	var button rect.Rect
  1136  	var content rect.Rect
  1137  	/* print currently selected text item */
  1138  
  1139  	var sym label.SymbolType
  1140  	if state&nstyle.WidgetStateHovered != 0 {
  1141  		sym = style.Combo.SymHover
  1142  	} else if is_active {
  1143  		sym = style.Combo.SymActive
  1144  	} else {
  1145  		sym = style.Combo.SymNormal
  1146  	}
  1147  
  1148  	/* calculate button */
  1149  	button.W = header.H - 2*style.Combo.ButtonPadding.Y
  1150  
  1151  	button.X = (header.X + header.W - header.H) - style.Combo.ButtonPadding.X
  1152  	button.Y = header.Y + style.Combo.ButtonPadding.Y
  1153  	button.H = button.W
  1154  
  1155  	content.X = button.X + style.Combo.Button.Padding.X
  1156  	content.Y = button.Y + style.Combo.Button.Padding.Y
  1157  	content.W = button.W - 2*style.Combo.Button.Padding.X
  1158  	content.H = button.H - 2*style.Combo.Button.Padding.Y
  1159  
  1160  	/* draw selected label */
  1161  	text.Padding = image.Point{0, 0}
  1162  
  1163  	var lblrect rect.Rect
  1164  	lblrect.X = header.X + style.Combo.ContentPadding.X
  1165  	lblrect.Y = header.Y + style.Combo.ContentPadding.Y
  1166  	lblrect.W = button.X - (style.Combo.ContentPadding.X + style.Combo.Spacing.X) - lblrect.X
  1167  	lblrect.H = header.H - 2*style.Combo.ContentPadding.Y
  1168  	widgetText(out, lblrect, selected, &text, "LC", style.Font)
  1169  
  1170  	/* draw open/close button */
  1171  	drawSymbolButton(win, button, content, state, &style.Combo.Button, sym)
  1172  }