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 }