widget/material: update Decorations

Fix actions not processed and move the Layout method from
Decorations to DecorationsStyle.

Also clarify the comment for the app.Window.Decorated option.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
Pierre Curto
2022-01-28 09:56:20 +01:00
committed by Elias Naur
parent 5ce1e98282
commit 030fd8a171
3 changed files with 58 additions and 58 deletions
+4 -4
View File
@@ -1068,11 +1068,11 @@ func (w *window) resize(a system.Action) {
case system.ActionResizeNorthWest: case system.ActionResizeNorthWest:
edge = C.XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT edge = C.XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT
case system.ActionResizeNorthEast: case system.ActionResizeNorthEast:
edge = C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT edge = C.XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT
case system.ActionResizeSouthEast: case system.ActionResizeSouthEast:
edge = C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT edge = C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT
case system.ActionResizeSouthWest: case system.ActionResizeSouthWest:
edge = C.XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT edge = C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT
default: default:
return return
} }
@@ -1115,9 +1115,9 @@ func (w *window) SetCursor(name pointer.CursorName) {
case pointer.CursorTopLeftResize: case pointer.CursorTopLeftResize:
name = "top_left_corner" name = "top_left_corner"
case pointer.CursorTopRightResize: case pointer.CursorTopRightResize:
name = "bottom_left_corner"
case pointer.CursorBottomLeftResize:
name = "top_right_corner" name = "top_right_corner"
case pointer.CursorBottomLeftResize:
name = "bottom_left_corner"
case pointer.CursorBottomRightResize: case pointer.CursorBottomRightResize:
name = "bottom_right_corner" name = "bottom_right_corner"
case pointer.CursorLeftResize: case pointer.CursorLeftResize:
+11 -11
View File
@@ -68,7 +68,7 @@ type Window struct {
decorations struct { decorations struct {
op.Ops op.Ops
Config Config
*material.Decorations *material.DecorationsStyle
} }
callbacks callbacks callbacks callbacks
@@ -688,7 +688,7 @@ func (w *Window) decorate(d driver, e system.FrameEvent, o *op.Ops) image.Point
if w.decorations.Config.Decorated || w.decorations.Config.Mode == Fullscreen { if w.decorations.Config.Decorated || w.decorations.Config.Mode == Fullscreen {
return e.Size return e.Size
} }
deco := w.decorations.Decorations deco := w.decorations.DecorationsStyle
if deco == nil { if deco == nil {
theme := material.NewTheme(gofont.Collection()) theme := material.NewTheme(gofont.Collection())
allActions := system.ActionMinimize | system.ActionMaximize | system.ActionUnmaximize | allActions := system.ActionMinimize | system.ActionMaximize | system.ActionUnmaximize |
@@ -697,10 +697,9 @@ func (w *Window) decorate(d driver, e system.FrameEvent, o *op.Ops) image.Point
system.ActionResizeWest | system.ActionResizeEast | system.ActionResizeWest | system.ActionResizeEast |
system.ActionResizeNorthWest | system.ActionResizeSouthWest | system.ActionResizeNorthWest | system.ActionResizeSouthWest |
system.ActionResizeNorthEast | system.ActionResizeSouthEast system.ActionResizeNorthEast | system.ActionResizeSouthEast
deco = &material.Decorations{ style := material.Decorate(theme, allActions)
DecorationsStyle: material.Decorate(theme, allActions), deco = &style
} w.decorations.DecorationsStyle = &style
w.decorations.Decorations = deco
} }
// Update the decorations based on the current window mode. // Update the decorations based on the current window mode.
var actions system.Action var actions system.Action
@@ -716,9 +715,9 @@ func (w *Window) decorate(d driver, e system.FrameEvent, o *op.Ops) image.Point
default: default:
panic(fmt.Errorf("unknown WindowMode %v", m)) panic(fmt.Errorf("unknown WindowMode %v", m))
} }
deco.Perform(actions) deco.Decorations.Perform(actions)
// Update the window based on the actions on the decorations. // Update the window based on the actions on the decorations.
d.Perform(deco.Actions()) d.Perform(deco.Decorations.Actions())
gtx := layout.Context{ gtx := layout.Context{
Ops: o, Ops: o,
@@ -728,7 +727,7 @@ func (w *Window) decorate(d driver, e system.FrameEvent, o *op.Ops) image.Point
Constraints: layout.Exact(e.Size), Constraints: layout.Exact(e.Size),
} }
rec := op.Record(o) rec := op.Record(o)
dims := deco.Decorate(gtx, w.decorations.Config.Title) dims := deco.Layout(gtx, w.decorations.Config.Title)
op.Defer(o, rec.Stop()) op.Defer(o, rec.Stop())
// Offset to place the frame content below the decorations. // Offset to place the frame content below the decorations.
size := image.Point{Y: dims.Size.Y} size := image.Point{Y: dims.Size.Y}
@@ -837,8 +836,9 @@ func CustomRenderer(custom bool) Option {
} }
} }
// Decorated controls whether automatic window decorations // Decorated controls whether Gio and/or the platform are responsible
// are enabled. // for drawing window decorations. Providing false indicates that
// the application will either be undecorated or will draw its own decorations.
func Decorated(enabled bool) Option { func Decorated(enabled bool) Option {
return func(_ unit.Metric, cnf *Config) { return func(_ unit.Metric, cnf *Config) {
cnf.Decorated = enabled cnf.Decorated = enabled
+43 -43
View File
@@ -19,6 +19,7 @@ import (
// DecorationsStyle provides the style elements for Decorations. // DecorationsStyle provides the style elements for Decorations.
type DecorationsStyle struct { type DecorationsStyle struct {
Decorations
Actions system.Action Actions system.Action
Title LabelStyle Title LabelStyle
Background color.NRGBA Background color.NRGBA
@@ -39,7 +40,6 @@ func Decorate(th *Theme, actions system.Action) DecorationsStyle {
// Decorations provides window decorations. // Decorations provides window decorations.
type Decorations struct { type Decorations struct {
DecorationsStyle
actions struct { actions struct {
layout.List layout.List
clicks []widget.Clickable clicks []widget.Clickable
@@ -54,22 +54,23 @@ type Decorations struct {
maximized bool maximized bool
} }
// Decorate a window with the title and actions defined in DecorationsStyle. // Layout a window with the title and actions defined in DecorationsStyle.
// The space used by the decorations is returned as an inset for the window func (d *DecorationsStyle) Layout(gtx layout.Context, title string) layout.Dimensions {
// content.
func (d *Decorations) Decorate(gtx layout.Context, title string) layout.Dimensions {
rec := op.Record(gtx.Ops) rec := op.Record(gtx.Ops)
dims := d.layoutDecorations(gtx, title) label := d.Title
label.Text = title
paint.ColorOp{Color: d.Foreground}.Add(gtx.Ops)
dims := d.Decorations.layoutDecorations(gtx, d.Actions, label.Layout)
decos := rec.Stop() decos := rec.Stop()
r := clip.Rect{Max: dims.Size} r := clip.Rect{Max: dims.Size}
paint.FillShape(gtx.Ops, d.DecorationsStyle.Background, r.Op()) paint.FillShape(gtx.Ops, d.Background, r.Op())
decos.Add(gtx.Ops) decos.Add(gtx.Ops)
d.layoutResizing(gtx) d.Decorations.layoutResizing(gtx, d.Actions)
return dims return dims
} }
func (d *Decorations) layoutResizing(gtx layout.Context) { func (d *Decorations) layoutResizing(gtx layout.Context, actions system.Action) {
cs := gtx.Constraints.Min cs := gtx.Constraints.Max
wh := gtx.Px(unit.Dp(10)) wh := gtx.Px(unit.Dp(10))
s := []struct { s := []struct {
system.Action system.Action
@@ -80,13 +81,13 @@ func (d *Decorations) layoutResizing(gtx layout.Context) {
{system.ActionResizeWest, image.Rect(cs.X-wh, 0, cs.X, cs.Y)}, {system.ActionResizeWest, image.Rect(cs.X-wh, 0, cs.X, cs.Y)},
{system.ActionResizeEast, image.Rect(0, 0, wh, cs.Y)}, {system.ActionResizeEast, image.Rect(0, 0, wh, cs.Y)},
{system.ActionResizeNorthWest, image.Rect(0, 0, wh, wh)}, {system.ActionResizeNorthWest, image.Rect(0, 0, wh, wh)},
{system.ActionResizeSouthWest, image.Rect(cs.X-wh, 0, cs.X, wh)}, {system.ActionResizeNorthEast, image.Rect(cs.X-wh, 0, cs.X, wh)},
{system.ActionResizeNorthEast, image.Rect(0, cs.Y-wh, wh, cs.Y)}, {system.ActionResizeSouthWest, image.Rect(0, cs.Y-wh, wh, cs.Y)},
{system.ActionResizeSouthEast, image.Rect(cs.X-wh, cs.Y-wh, cs.X, cs.Y)}, {system.ActionResizeSouthEast, image.Rect(cs.X-wh, cs.Y-wh, cs.X, cs.Y)},
} }
for i, data := range s { for i, data := range s {
action := data.Action action := data.Action
if d.DecorationsStyle.Actions&action == 0 { if actions&action == 0 {
continue continue
} }
rsz := &d.actions.resize[i] rsz := &d.actions.resize[i]
@@ -106,7 +107,7 @@ func (d *Decorations) layoutResizing(gtx layout.Context) {
} }
} }
func (d *Decorations) layoutDecorations(gtx layout.Context, title string) layout.Dimensions { func (d *Decorations) layoutDecorations(gtx layout.Context, actions system.Action, title layout.Widget) layout.Dimensions {
gtx.Constraints.Min.Y = 0 gtx.Constraints.Min.Y = 0
inset := layout.UniformInset(unit.Dp(10)) inset := layout.UniformInset(unit.Dp(10))
return layout.Flex{ return layout.Flex{
@@ -115,9 +116,8 @@ func (d *Decorations) layoutDecorations(gtx layout.Context, title string) layout
Spacing: layout.SpaceBetween, Spacing: layout.SpaceBetween,
}.Layout(gtx, }.Layout(gtx,
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions { layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
d.DecorationsStyle.Title.Text = title dims := inset.Layout(gtx, title)
dims := inset.Layout(gtx, d.DecorationsStyle.Title.Layout) if actions&system.ActionMove != 0 {
if d.DecorationsStyle.Actions&system.ActionMove != 0 {
d.actions.move.Events(gtx.Metric, gtx, gesture.Both) d.actions.move.Events(gtx.Metric, gtx, gesture.Both)
st := clip.Rect{Max: dims.Size}.Push(gtx.Ops) st := clip.Rect{Max: dims.Size}.Push(gtx.Ops)
@@ -131,27 +131,16 @@ func (d *Decorations) layoutDecorations(gtx layout.Context, title string) layout
}), }),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
// Remove the unmaximize action as it is taken care of by maximize. // Remove the unmaximize action as it is taken care of by maximize.
actions := d.DecorationsStyle.Actions &^ system.ActionUnmaximize actions := actions &^ system.ActionUnmaximize
an := bits.OnesCount(uint(actions)) an := bits.OnesCount(uint(actions))
if n := len(d.actions.clicks); n < an { if n := len(d.actions.clicks); n < an {
d.actions.clicks = append(d.actions.clicks, make([]widget.Clickable, an-n)...) d.actions.clicks = append(d.actions.clicks, make([]widget.Clickable, an-n)...)
} }
action := system.Action(1)
return d.actions.Layout(gtx, an, func(gtx layout.Context, idx int) layout.Dimensions { return d.actions.Layout(gtx, an, func(gtx layout.Context, idx int) layout.Dimensions {
action := system.Action(1 << idx) defer func() { action <<= 1 }()
var w layout.Widget for actions&action == 0 {
switch actions & action { action <<= 1
case system.ActionMinimize:
w = d.minimizeWindow
case system.ActionMaximize:
if d.maximized {
w = d.maximizedWindow
} else {
w = d.maximizeWindow
}
case system.ActionClose:
w = d.closeWindow
default:
return layout.Dimensions{}
} }
click := &d.actions.clicks[idx] click := &d.actions.clicks[idx]
if click.Clicked() { if click.Clicked() {
@@ -168,6 +157,21 @@ func (d *Decorations) layoutDecorations(gtx layout.Context, title string) layout
} }
} }
return Clickable(gtx, click, func(gtx layout.Context) layout.Dimensions { return Clickable(gtx, click, func(gtx layout.Context) layout.Dimensions {
var w layout.Widget
switch actions & action {
case system.ActionMinimize:
w = minimizeWindow
case system.ActionMaximize:
if d.maximized {
w = maximizedWindow
} else {
w = maximizeWindow
}
case system.ActionClose:
w = closeWindow
default:
return layout.Dimensions{}
}
return inset.Layout(gtx, w) return inset.Layout(gtx, w)
}) })
}) })
@@ -200,13 +204,12 @@ var (
) )
// minimizeWindows draws a line icon representing the minimize action. // minimizeWindows draws a line icon representing the minimize action.
func (d *Decorations) minimizeWindow(gtx layout.Context) layout.Dimensions { func minimizeWindow(gtx layout.Context) layout.Dimensions {
paint.ColorOp{Color: d.DecorationsStyle.Foreground}.Add(gtx.Ops)
size := gtx.Px(winIconSize) size := gtx.Px(winIconSize)
size32 := float32(size) size32 := float32(size)
margin := float32(gtx.Px(winIconMargin)) margin := float32(gtx.Px(winIconMargin))
width := float32(gtx.Px(winIconStroke)) width := float32(gtx.Px(winIconStroke))
p := &d.path var p clip.Path
p.Begin(gtx.Ops) p.Begin(gtx.Ops)
p.MoveTo(f32.Point{X: margin, Y: size32 - margin}) p.MoveTo(f32.Point{X: margin, Y: size32 - margin})
p.LineTo(f32.Point{X: size32 - 2*margin, Y: size32 - margin}) p.LineTo(f32.Point{X: size32 - 2*margin, Y: size32 - margin})
@@ -220,8 +223,7 @@ func (d *Decorations) minimizeWindow(gtx layout.Context) layout.Dimensions {
} }
// maximizeWindow draws a rectangle representing the maximize action. // maximizeWindow draws a rectangle representing the maximize action.
func (d *Decorations) maximizeWindow(gtx layout.Context) layout.Dimensions { func maximizeWindow(gtx layout.Context) layout.Dimensions {
paint.ColorOp{Color: d.DecorationsStyle.Foreground}.Add(gtx.Ops)
size := gtx.Px(winIconSize) size := gtx.Px(winIconSize)
size32 := float32(size) size32 := float32(size)
margin := float32(gtx.Px(winIconMargin)) margin := float32(gtx.Px(winIconMargin))
@@ -245,8 +247,7 @@ func (d *Decorations) maximizeWindow(gtx layout.Context) layout.Dimensions {
} }
// maximizedWindow draws interleaved rectangles representing the un-maximize action. // maximizedWindow draws interleaved rectangles representing the un-maximize action.
func (d *Decorations) maximizedWindow(gtx layout.Context) layout.Dimensions { func maximizedWindow(gtx layout.Context) layout.Dimensions {
paint.ColorOp{Color: d.DecorationsStyle.Foreground}.Add(gtx.Ops)
size := gtx.Px(winIconSize) size := gtx.Px(winIconSize)
size32 := float32(size) size32 := float32(size)
margin := float32(gtx.Px(winIconMargin)) margin := float32(gtx.Px(winIconMargin))
@@ -273,13 +274,12 @@ func (d *Decorations) maximizedWindow(gtx layout.Context) layout.Dimensions {
} }
// closeWindow draws a cross representing the close action. // closeWindow draws a cross representing the close action.
func (d *Decorations) closeWindow(gtx layout.Context) layout.Dimensions { func closeWindow(gtx layout.Context) layout.Dimensions {
paint.ColorOp{Color: d.DecorationsStyle.Foreground}.Add(gtx.Ops)
size := gtx.Px(winIconSize) size := gtx.Px(winIconSize)
size32 := float32(size) size32 := float32(size)
margin := float32(gtx.Px(winIconMargin)) margin := float32(gtx.Px(winIconMargin))
width := float32(gtx.Px(winIconStroke)) width := float32(gtx.Px(winIconStroke))
p := &d.path var p clip.Path
p.Begin(gtx.Ops) p.Begin(gtx.Ops)
p.MoveTo(f32.Point{X: margin, Y: margin}) p.MoveTo(f32.Point{X: margin, Y: margin})
p.LineTo(f32.Point{X: size32 - margin, Y: size32 - margin}) p.LineTo(f32.Point{X: size32 - margin, Y: size32 - margin})