Added Disabled to controls.

This commit is contained in:
Sander Schobers 2020-05-16 13:46:07 +02:00
parent d673653d3f
commit ae46d2a1f2
11 changed files with 180 additions and 31 deletions

View File

@ -13,6 +13,8 @@ type Button struct {
Icon string
Text string
Type ButtonType
clicked ControlClickedEvents
}
type ButtonType int
@ -59,19 +61,48 @@ func (b *Button) icon(ctx Context) Texture {
return ctx.Textures().Texture(b.Icon)
}
func (b *Button) ButtonClicked() ControlClickedEventHandler { return &b.clicked }
func (b *Button) DesiredSize(ctx Context) geom.PointF32 {
return b.desiredSize(ctx)
}
func (b *Button) Handle(ctx Context, e Event) bool {
result := b.ControlBase.Handle(ctx, e)
result := b.ControlBase.HandleNotify(ctx, e, b)
if b.over {
if b.Disabled {
ctx.Renderer().SetMouseCursor(MouseCursorNotAllowed)
return true
}
ctx.Renderer().SetMouseCursor(MouseCursorPointer)
}
return result
}
func (b *Button) Notify(ctx Context, state interface{}) bool {
switch state.(type) {
case ControlClickedArgs:
if !b.Disabled {
if b.clicked.Notify(ctx, state) {
return true
}
}
}
return b.ControlBase.Notify(ctx, state)
}
func (b *Button) fillColor(p *Palette) color.Color {
if b.Disabled {
if b.Background != nil {
return p.Disabled
}
switch b.Type {
case ButtonTypeContained:
return p.Disabled
default:
return nil
}
}
if b.Background != nil {
if b.over && b.HoverColor != nil {
return b.HoverColor
@ -100,6 +131,16 @@ func (b *Button) fillColor(p *Palette) color.Color {
}
func (b *Button) textColor(p *Palette) color.Color {
if b.Disabled {
if b.Background != nil {
return p.TextOnDisabled
}
switch b.Type {
case ButtonTypeContained:
return p.TextOnDisabled
}
return p.Disabled
}
if b.Font.Color != nil {
return b.Font.Color
}
@ -151,6 +192,6 @@ func (b *Button) Render(ctx Context) {
}
if b.Type == ButtonTypeOutlined {
b.RenderOutline(ctx)
b.RenderOutlineDefault(ctx, textColor)
}
}

View File

@ -37,7 +37,7 @@ func (c *Checkbox) desiredSize(ctx Context) geom.PointF32 {
func (c *Checkbox) icon(ctx Context) Texture {
if c.Selected {
return GetOrCreateIcon(ctx, "ui-default-checkbox-selected", c.selectedIcon)
} else if c.over {
} else if c.over && !c.Disabled {
return GetOrCreateIcon(ctx, "ui-default-checkbox-hover", c.hoverIcon)
}
return c.getOrCreateNormalIcon(ctx)
@ -80,6 +80,10 @@ func (c *Checkbox) DesiredSize(ctx Context) geom.PointF32 { return c.desiredSize
func (c *Checkbox) Handle(ctx Context, e Event) bool {
result := c.ControlBase.Handle(ctx, e)
if c.over {
if c.Disabled {
ctx.Renderer().SetMouseCursor(MouseCursorNotAllowed)
return true
}
ctx.Renderer().SetMouseCursor(MouseCursorPointer)
}
if result {
@ -102,7 +106,7 @@ func (c *Checkbox) Render(ctx Context) {
var style = ctx.Style()
var palette = style.Palette
fore := c.FontColor(ctx)
fore := c.TextColor(ctx)
bounds := c.bounds
var pad = style.Dimensions.TextPadding
@ -112,8 +116,8 @@ func (c *Checkbox) Render(ctx Context) {
icon := c.icon(ctx)
if icon != nil {
iconColor := fore
if c.Selected && c.Font.Color == nil {
iconColor = palette.Primary
if c.Selected {
iconColor = c.FontColor(ctx, palette.Primary)
}
scaledIcon, _ := ctx.Textures().ScaledHeight(icon, boundsH) // try to pre-scale icon
if scaledIcon == nil { // let the renderer scale

View File

@ -11,6 +11,9 @@ type Control interface {
Render(Context)
Bounds() geom.RectangleF32
Disable()
Enable()
IsDisabled() bool
IsInBounds(p geom.PointF32) bool
IsOver() bool
Offset() geom.PointF32

View File

@ -104,6 +104,8 @@ type ControlBase struct {
Font FontStyle
TextAlignment HorizontalAlignment
Disabled bool
Tooltip string
}
@ -115,9 +117,23 @@ func (c *ControlBase) Arrange(ctx Context, bounds geom.RectangleF32, offset geom
func (c *ControlBase) Bounds() geom.RectangleF32 { return c.bounds }
func (c *ControlBase) ControlClicked() ControlClickedEventHandler { return &c.clicked }
func (c *ControlBase) DesiredSize(Context) geom.PointF32 { return geom.ZeroPtF32 }
func (c *ControlBase) Handle(ctx Context, e Event) bool {
func (c *ControlBase) Disable() { c.Disabled = true }
func (c *ControlBase) DragEnded() DragEndedEventHandler { return &c.dragEnded }
func (c *ControlBase) DragMoved() DragMovedEventHandler { return &c.dragMoved }
func (c *ControlBase) DragStarted() DragStartedEventHandler { return &c.dragStarted }
func (c *ControlBase) Enable() { c.Disabled = false }
func (c *ControlBase) Handle(ctx Context, e Event) bool { return c.HandleNotify(ctx, e, c) }
func (c *ControlBase) HandleNotify(ctx Context, e Event, notifier Notifier) bool {
defer func() {
if c.Tooltip != "" && c.over {
ctx.ShowTooltip(c.Tooltip)
@ -145,11 +161,11 @@ func (c *ControlBase) Handle(ctx Context, e Event) bool {
if start, ok := c.drag.IsDragging(); ok {
var move = c.ToControlPosition(e.Pos())
c.drag.Move(move)
return c.dragMoved.Notify(ctx, DragMovedArgs{Start: start, Current: move})
return notifier.Notify(ctx, DragMovedArgs{Start: start, Current: move})
}
var start = c.ToControlPosition(e.Pos())
c.drag.Start(start)
return c.dragStarted.Notify(ctx, DragStartedArgs{Start: start})
return notifier.Notify(ctx, DragStartedArgs{Start: start})
}
case *MouseLeaveEvent:
c.over = false
@ -157,7 +173,7 @@ func (c *ControlBase) Handle(ctx Context, e Event) bool {
c.over = over(e.MouseEvent)
if c.over && e.Button == MouseButtonLeft {
c.pressed = true
return c.clicked.Notify(ctx, ControlClickedArgs{Position: e.Pos(), Button: e.Button})
return notifier.Notify(ctx, ControlClickedArgs{Position: e.Pos(), Button: e.Button})
}
case *MouseButtonUpEvent:
if e.Button == MouseButtonLeft {
@ -165,17 +181,20 @@ func (c *ControlBase) Handle(ctx Context, e Event) bool {
if start, ok := c.drag.IsDragging(); ok {
var end = c.ToControlPosition(e.Pos())
c.drag.Cancel()
return c.dragEnded.Notify(ctx, DragEndedArgs{Start: start, End: end})
return notifier.Notify(ctx, DragEndedArgs{Start: start, End: end})
}
}
}
return false
}
func (c *ControlBase) FontColor(ctx Context) color.Color {
func (c *ControlBase) FontColor(ctx Context, color color.Color) color.Color {
if c.Disabled {
return ctx.Style().Palette.TextOnDisabled
}
var text = c.Font.Color
if text == nil {
text = ctx.Style().Palette.Text
text = color
}
return text
}
@ -188,6 +207,8 @@ func (c *ControlBase) FontName(ctx Context) string {
return name
}
func (c *ControlBase) IsDisabled() bool { return c.Disabled }
func (c *ControlBase) IsInBounds(p geom.PointF32) bool {
bounds := c.bounds
if bounds.Min.X < 0 {
@ -201,19 +222,30 @@ func (c *ControlBase) IsInBounds(p geom.PointF32) bool {
func (c *ControlBase) IsOver() bool { return c.over }
func (c *ControlBase) Parent() Control { return c.parent }
func (c *ControlBase) IsPressed() bool { return c.pressed }
func (c *ControlBase) Notify(ctx Context, state interface{}) bool {
switch state.(type) {
case ControlClickedArgs:
return c.clicked.Notify(ctx, state)
case DragEndedArgs:
return c.dragEnded.Notify(ctx, state)
case DragMovedArgs:
return c.dragMoved.Notify(ctx, state)
case DragStartedArgs:
return c.dragStarted.Notify(ctx, state)
default:
return false
}
}
func (c *ControlBase) Parent() Control { return c.parent }
func (c *ControlBase) Offset() geom.PointF32 { return c.offset }
func (c *ControlBase) ControlClicked() ControlClickedEventHandler { return &c.clicked }
func (c *ControlBase) DragEnded() DragEndedEventHandler { return &c.dragEnded }
func (c *ControlBase) DragMoved() DragMovedEventHandler { return &c.dragMoved }
func (c *ControlBase) DragStarted() DragStartedEventHandler { return &c.dragStarted }
func (c *ControlBase) OutlineColor(ctx Context) color.Color {
return c.FontColor(ctx, ctx.Style().Palette.Primary)
}
func (c *ControlBase) Render(Context) {}
@ -224,13 +256,20 @@ func (c *ControlBase) RenderBackground(ctx Context) {
}
func (c *ControlBase) RenderOutline(ctx Context) {
c.RenderOutlineDefault(ctx, nil)
}
func (c *ControlBase) RenderOutlineDefault(ctx Context, color color.Color) {
style := ctx.Style()
width := style.Dimensions.OutlineWidth
color := style.Palette.Primary
if c.Font.Color != nil {
color = c.Font.Color
if color == nil {
color = c.OutlineColor(ctx)
}
ctx.Renderer().Rectangle(c.bounds.Inset(.5*width), color, width)
}
func (c *ControlBase) TextColor(ctx Context) color.Color {
return c.FontColor(ctx, ctx.Style().Palette.Text)
}
func (c *ControlBase) ToControlPosition(p geom.PointF32) geom.PointF32 { return p.Sub(c.offset) }

View File

@ -47,22 +47,62 @@ func (b *basic) Init(ctx ui.Context) error {
stretch(ui.BuildIconButton("plus", "Text", func(b *ui.Button) { b.Type = ui.ButtonTypeText }), 8),
}
}),
ui.BuildStackPanel(ui.OrientationHorizontal, func(p *ui.StackPanel) {
p.Children = []ui.Control{
stretch(ui.BuildIconButton("plus", "Contained", func(b *ui.Button) {
b.Type = ui.ButtonTypeContained
b.Disabled = true
}), 8),
stretch(ui.BuildIconButton("plus", "Icon", func(b *ui.Button) {
b.Type = ui.ButtonTypeIcon
b.Disabled = true
}), 8),
stretch(ui.BuildIconButton("plus", "Outlined", func(b *ui.Button) {
b.Type = ui.ButtonTypeOutlined
b.Disabled = true
}), 8),
stretch(ui.BuildIconButton("plus", "Text", func(b *ui.Button) {
b.Type = ui.ButtonTypeText
b.Disabled = true
}), 8),
}
}),
ui.BuildStackPanel(ui.OrientationHorizontal, func(p *ui.StackPanel) {
p.Children = []ui.Control{
&ui.Checkbox{},
ui.BuildCheckbox("Check me!", nil),
}
}),
ui.BuildStackPanel(ui.OrientationHorizontal, func(p *ui.StackPanel) {
p.Children = []ui.Control{
ui.BuildCheckbox("", func(b *ui.Checkbox) { b.Disabled = true }),
ui.BuildCheckbox("You can't check me!", func(b *ui.Checkbox) {
b.Selected = true
b.Disabled = true
}),
}
}),
ui.Stretch(&ui.Label{Text: "Content"}),
ui.Margin(ui.StretchWidth(ui.BuildTextBox(func(b *ui.TextBox) {
b.Text = "Type here..."
})), 8),
ui.Margin(ui.StretchWidth(ui.BuildTextBox(func(b *ui.TextBox) {
b.Text = "You can't type here..."
b.Disabled = true
})), 8),
ui.Margin(ui.BuildButton("Quit", func(b *ui.Button) {
b.ControlClicked().AddHandler(func(ui.Context, ui.ControlClickedArgs) {
b.ButtonClicked().AddHandler(func(ui.Context, ui.ControlClickedArgs) {
ctx.Quit()
})
b.Tooltip = "Will quit the application"
}), 8),
ui.Margin(ui.BuildButton("Can't quit", func(b *ui.Button) {
b.ButtonClicked().AddHandler(func(ui.Context, ui.ControlClickedArgs) {
ctx.Quit()
})
b.Tooltip = "Will not quit the application"
b.Disabled = true
}), 8),
ui.BuildLabel("Status...", func(l *ui.Label) {
l.Background = style.Palette.PrimaryDark
l.Font.Color = style.Palette.TextOnPrimary

View File

@ -49,7 +49,7 @@ func (l *Label) DesiredSize(ctx Context) geom.PointF32 {
func (l *Label) Render(ctx Context) {
l.RenderBackground(ctx)
fontColor := l.FontColor(ctx)
fontColor := l.TextColor(ctx)
fontName := l.FontName(ctx)
pad := ctx.Style().Dimensions.TextPadding
bounds := l.bounds.Inset(pad)

5
ui/notifier.go Normal file
View File

@ -0,0 +1,5 @@
package ui
type Notifier interface {
Notify(Context, interface{}) bool
}

View File

@ -28,6 +28,12 @@ func (p *Proxy) Bounds() geom.RectangleF32 {
return p.Content.Bounds()
}
func (p *Proxy) Disable() { p.Content.Disable() }
func (p *Proxy) Enable() { p.Content.Enable() }
func (p *Proxy) IsDisabled() bool { return p.Content.IsDisabled() }
func (p *Proxy) IsInBounds(pt geom.PointF32) bool { return p.Content.IsInBounds(pt) }
func (p *Proxy) IsOver() bool { return p.Content.IsOver() }

View File

@ -165,6 +165,10 @@ func (h *sliderHandle) texture(ctx Context) Texture {
func (h *sliderHandle) Handle(ctx Context, e Event) bool {
h.ControlBase.Handle(ctx, e)
if h.IsOver() {
if h.Disabled {
ctx.Renderer().SetMouseCursor(MouseCursorNotAllowed)
return true
}
ctx.Renderer().SetMouseCursor(MouseCursorPointer)
}
return true

View File

@ -25,6 +25,8 @@ type FontNames struct {
type Palette struct {
// Background is the default background color.
Background color.Color
// Disabled is the color to use when the control is disabled.
Disabled color.Color
// Primary is used as a the main contrast color.
Primary color.Color
// PrimaryDark is a foreground version of the main contrast color.
@ -45,10 +47,10 @@ type Palette struct {
ShadedBackground color.Color
// Text is the default text color.
Text color.Color
// TextDisabled is disabled text color.
TextDisabled color.Color
// TextNegative is the text color associated with a negative event.
TextNegative color.Color
// TextOnDisabled is text color rendered over an disabled control.
TextOnDisabled color.Color
// TextOnPrimary is the text color when used with the main contrast color as background.
TextOnPrimary color.Color
// TextOnSecondary is the text color when used with the secondary contrast color as background.
@ -81,6 +83,7 @@ func DefaultFontNames() *FontNames {
func DefaultPalette() *Palette {
return &Palette{
Background: color.White,
Disabled: zntg.MustHexColor(`#BDBDBD`),
Primary: zntg.MustHexColor(`#3F51B5`),
PrimaryDark: zntg.MustHexColor(`#132584`),
@ -95,8 +98,8 @@ func DefaultPalette() *Palette {
ShadedBackground: zntg.MustHexColor(`#FAFAFA`),
Text: color.Black,
TextDisabled: zntg.MustHexColor(`#BDBDBD`),
TextNegative: zntg.MustHexColor(`#FF4336`),
TextOnDisabled: zntg.MustHexColor(`#5C5C5C`),
TextOnPrimary: color.White,
TextOnSecondary: color.Black,
TextPositive: zntg.MustHexColor(`#4CAF50`),

View File

@ -132,6 +132,10 @@ func (b *TextBox) Handle(ctx Context, e Event) bool {
b.box.Handle(ctx, e)
if b.over {
if b.Disabled {
ctx.Renderer().SetMouseCursor(MouseCursorNotAllowed)
return true
}
ctx.Renderer().SetMouseCursor(MouseCursorText)
}
ctx.Animate()
@ -241,7 +245,7 @@ func (b *TextBox) Render(ctx Context) {
b.RenderBackground(ctx)
b.RenderOutline(ctx)
c := b.FontColor(ctx)
c := b.TextColor(ctx)
style := ctx.Style()
var caretWidth float32 = 1
b.box.RenderFn(ctx, func(_ Context, size geom.PointF32) {