mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-04 17:05:38 +00:00
widget/material: split Decorations state and style
Move Decorations to the widget package and rename material.Decorate to material.Decorations. This makes decorations in line with how the other widgets are used. Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
+39
-20
@@ -22,6 +22,7 @@ import (
|
|||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
"gioui.org/unit"
|
"gioui.org/unit"
|
||||||
|
"gioui.org/widget"
|
||||||
"gioui.org/widget/material"
|
"gioui.org/widget/material"
|
||||||
|
|
||||||
_ "gioui.org/app/internal/log"
|
_ "gioui.org/app/internal/log"
|
||||||
@@ -68,7 +69,9 @@ type Window struct {
|
|||||||
decorations struct {
|
decorations struct {
|
||||||
op.Ops
|
op.Ops
|
||||||
Config
|
Config
|
||||||
*material.DecorationsStyle
|
*material.Theme
|
||||||
|
*widget.Decorations
|
||||||
|
size image.Point // decorations size
|
||||||
}
|
}
|
||||||
|
|
||||||
callbacks callbacks
|
callbacks callbacks
|
||||||
@@ -620,8 +623,14 @@ func (w *Window) processEvent(d driver, e event.Event) {
|
|||||||
w.waitAck(d)
|
w.waitAck(d)
|
||||||
case wakeupEvent:
|
case wakeupEvent:
|
||||||
case ConfigEvent:
|
case ConfigEvent:
|
||||||
|
if w.decorations.Config.Decorated != e2.Config.Decorated && e2.Config.Decorated {
|
||||||
|
// Decorations are no longer applied.
|
||||||
|
w.decorations.Decorations = nil
|
||||||
|
w.decorations.size = image.Point{}
|
||||||
|
}
|
||||||
w.decorations.Config = e2.Config
|
w.decorations.Config = e2.Config
|
||||||
w.out <- e
|
e2.Config.Size = e2.Config.Size.Sub(w.decorations.size)
|
||||||
|
w.out <- e2
|
||||||
case event.Event:
|
case event.Event:
|
||||||
if w.queue.q.Queue(e2) {
|
if w.queue.q.Queue(e2) {
|
||||||
w.setNextFrame(time.Time{})
|
w.setNextFrame(time.Time{})
|
||||||
@@ -685,19 +694,23 @@ 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.DecorationsStyle
|
theme := w.decorations.Theme
|
||||||
if deco == nil {
|
if theme == nil {
|
||||||
theme := material.NewTheme(gofont.Collection())
|
theme = material.NewTheme(gofont.Collection())
|
||||||
allActions := system.ActionMinimize | system.ActionMaximize | system.ActionUnmaximize |
|
w.decorations.Theme = theme
|
||||||
system.ActionClose | system.ActionMove |
|
|
||||||
system.ActionResizeNorth | system.ActionResizeSouth |
|
|
||||||
system.ActionResizeWest | system.ActionResizeEast |
|
|
||||||
system.ActionResizeNorthWest | system.ActionResizeSouthWest |
|
|
||||||
system.ActionResizeNorthEast | system.ActionResizeSouthEast
|
|
||||||
style := material.Decorate(theme, allActions)
|
|
||||||
deco = &style
|
|
||||||
w.decorations.DecorationsStyle = &style
|
|
||||||
}
|
}
|
||||||
|
deco := w.decorations.Decorations
|
||||||
|
if deco == nil {
|
||||||
|
deco = new(widget.Decorations)
|
||||||
|
w.decorations.Decorations = deco
|
||||||
|
}
|
||||||
|
allActions := system.ActionMinimize | system.ActionMaximize | system.ActionUnmaximize |
|
||||||
|
system.ActionClose | system.ActionMove |
|
||||||
|
system.ActionResizeNorth | system.ActionResizeSouth |
|
||||||
|
system.ActionResizeWest | system.ActionResizeEast |
|
||||||
|
system.ActionResizeNorthWest | system.ActionResizeSouthWest |
|
||||||
|
system.ActionResizeNorthEast | system.ActionResizeSouthEast
|
||||||
|
style := material.Decorations(theme, deco, allActions, w.decorations.Config.Title)
|
||||||
// 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
|
||||||
switch m := w.decorations.Config.Mode; m {
|
switch m := w.decorations.Config.Mode; m {
|
||||||
@@ -712,10 +725,7 @@ 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.Decorations.Perform(actions)
|
deco.Perform(actions)
|
||||||
// Update the window based on the actions on the decorations.
|
|
||||||
d.Perform(deco.Decorations.Actions())
|
|
||||||
|
|
||||||
gtx := layout.Context{
|
gtx := layout.Context{
|
||||||
Ops: o,
|
Ops: o,
|
||||||
Now: e.Now,
|
Now: e.Now,
|
||||||
@@ -724,12 +734,21 @@ 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.Layout(gtx, w.decorations.Config.Title)
|
dims := style.Layout(gtx)
|
||||||
op.Defer(o, rec.Stop())
|
op.Defer(o, rec.Stop())
|
||||||
|
// Update the window based on the actions on the decorations.
|
||||||
|
d.Perform(deco.Actions())
|
||||||
// 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}
|
||||||
op.Offset(f32.Point{Y: float32(size.Y)}).Add(o)
|
op.Offset(f32.Point{Y: float32(size.Y)}).Add(o)
|
||||||
return e.Size.Sub(size)
|
appSize := e.Size.Sub(size)
|
||||||
|
if w.decorations.size != size {
|
||||||
|
w.decorations.size = size
|
||||||
|
cnf := w.decorations.Config
|
||||||
|
cnf.Size = appSize
|
||||||
|
w.out <- ConfigEvent{Config: cnf}
|
||||||
|
}
|
||||||
|
return appSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raise requests that the platform bring this window to the top of all open windows.
|
// Raise requests that the platform bring this window to the top of all open windows.
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package widget
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"math/bits"
|
||||||
|
|
||||||
|
"gioui.org/gesture"
|
||||||
|
"gioui.org/io/pointer"
|
||||||
|
"gioui.org/io/system"
|
||||||
|
"gioui.org/layout"
|
||||||
|
"gioui.org/op/clip"
|
||||||
|
"gioui.org/unit"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decorations handles the states of window decorations.
|
||||||
|
type Decorations struct {
|
||||||
|
move gesture.Drag
|
||||||
|
clicks []Clickable
|
||||||
|
resize [8]struct {
|
||||||
|
gesture.Hover
|
||||||
|
gesture.Drag
|
||||||
|
}
|
||||||
|
actions system.Action
|
||||||
|
maximized bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// LayoutMove lays out the widget that makes a window movable.
|
||||||
|
func (d *Decorations) LayoutMove(gtx layout.Context, w layout.Widget) layout.Dimensions {
|
||||||
|
dims := w(gtx)
|
||||||
|
d.move.Events(gtx.Metric, gtx, gesture.Both)
|
||||||
|
st := clip.Rect{Max: dims.Size}.Push(gtx.Ops)
|
||||||
|
d.move.Add(gtx.Ops)
|
||||||
|
if d.move.Pressed() {
|
||||||
|
d.actions |= system.ActionMove
|
||||||
|
}
|
||||||
|
st.Pop()
|
||||||
|
return dims
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clickable returns the clickable for the given single action.
|
||||||
|
func (d *Decorations) Clickable(action system.Action) *Clickable {
|
||||||
|
if bits.OnesCount(uint(action)) != 1 {
|
||||||
|
panic(fmt.Errorf("not a single action"))
|
||||||
|
}
|
||||||
|
idx := bits.TrailingZeros(uint(action))
|
||||||
|
if n := idx - len(d.clicks); n >= 0 {
|
||||||
|
d.clicks = append(d.clicks, make([]Clickable, n+1)...)
|
||||||
|
}
|
||||||
|
click := &d.clicks[idx]
|
||||||
|
if click.Clicked() {
|
||||||
|
if action == system.ActionMaximize {
|
||||||
|
if d.maximized {
|
||||||
|
d.maximized = false
|
||||||
|
d.actions |= system.ActionUnmaximize
|
||||||
|
} else {
|
||||||
|
d.maximized = true
|
||||||
|
d.actions |= system.ActionMaximize
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d.actions |= action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return click
|
||||||
|
}
|
||||||
|
|
||||||
|
// LayoutResize lays out the resize actions.
|
||||||
|
func (d *Decorations) LayoutResize(gtx layout.Context, actions system.Action) {
|
||||||
|
cs := gtx.Constraints.Max
|
||||||
|
wh := gtx.Px(unit.Dp(10))
|
||||||
|
s := []struct {
|
||||||
|
system.Action
|
||||||
|
image.Rectangle
|
||||||
|
}{
|
||||||
|
{system.ActionResizeNorth, image.Rect(0, 0, cs.X, wh)},
|
||||||
|
{system.ActionResizeSouth, image.Rect(0, cs.Y-wh, 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.ActionResizeNorthWest, image.Rect(0, 0, wh, wh)},
|
||||||
|
{system.ActionResizeNorthEast, image.Rect(cs.X-wh, 0, cs.X, wh)},
|
||||||
|
{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)},
|
||||||
|
}
|
||||||
|
for i, data := range s {
|
||||||
|
action := data.Action
|
||||||
|
if actions&action == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rsz := &d.resize[i]
|
||||||
|
rsz.Events(gtx.Metric, gtx, gesture.Both)
|
||||||
|
if rsz.Drag.Dragging() {
|
||||||
|
d.actions |= action
|
||||||
|
}
|
||||||
|
st := clip.Rect(data.Rectangle).Push(gtx.Ops)
|
||||||
|
if rsz.Hover.Hovered(gtx) {
|
||||||
|
pointer.CursorNameOp{Name: action.CursorName()}.Add(gtx.Ops)
|
||||||
|
}
|
||||||
|
rsz.Drag.Add(gtx.Ops)
|
||||||
|
pass := pointer.PassOp{}.Push(gtx.Ops)
|
||||||
|
rsz.Hover.Add(gtx.Ops)
|
||||||
|
pass.Pop()
|
||||||
|
st.Pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform updates the decorations as if the specified actions were
|
||||||
|
// performed by the user.
|
||||||
|
func (d *Decorations) Perform(actions system.Action) {
|
||||||
|
if actions&system.ActionMaximize != 0 {
|
||||||
|
d.maximized = true
|
||||||
|
}
|
||||||
|
if actions&(system.ActionUnmaximize|system.ActionMinimize|system.ActionFullscreen) != 0 {
|
||||||
|
d.maximized = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actions returns the set of actions activated by the user.
|
||||||
|
func (d *Decorations) Actions() system.Action {
|
||||||
|
a := d.actions
|
||||||
|
d.actions = 0
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maximized returns whether the window is maximized.
|
||||||
|
func (d *Decorations) Maximized() bool {
|
||||||
|
return d.maximized
|
||||||
|
}
|
||||||
+58
-152
@@ -3,11 +3,8 @@ package material
|
|||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"math/bits"
|
|
||||||
|
|
||||||
"gioui.org/f32"
|
"gioui.org/f32"
|
||||||
"gioui.org/gesture"
|
|
||||||
"gioui.org/io/pointer"
|
|
||||||
"gioui.org/io/system"
|
"gioui.org/io/system"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
@@ -19,95 +16,42 @@ import (
|
|||||||
|
|
||||||
// DecorationsStyle provides the style elements for Decorations.
|
// DecorationsStyle provides the style elements for Decorations.
|
||||||
type DecorationsStyle struct {
|
type DecorationsStyle struct {
|
||||||
Decorations
|
Decorations *widget.Decorations
|
||||||
Actions system.Action
|
Actions system.Action
|
||||||
Title LabelStyle
|
Title LabelStyle
|
||||||
Background color.NRGBA
|
Background color.NRGBA
|
||||||
Foreground color.NRGBA
|
Foreground color.NRGBA
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decorate a window.
|
// Decorations returns the style to decorate a window.
|
||||||
func Decorate(th *Theme, actions system.Action) DecorationsStyle {
|
func Decorations(th *Theme, deco *widget.Decorations, actions system.Action, title string) DecorationsStyle {
|
||||||
titleStyle := Body1(th, "")
|
titleStyle := Body1(th, title)
|
||||||
titleStyle.Color = th.Palette.ContrastFg
|
titleStyle.Color = th.Palette.ContrastFg
|
||||||
return DecorationsStyle{
|
return DecorationsStyle{
|
||||||
Actions: actions,
|
Decorations: deco,
|
||||||
Title: titleStyle,
|
Actions: actions,
|
||||||
Background: th.Palette.ContrastBg,
|
Title: titleStyle,
|
||||||
Foreground: th.Palette.ContrastFg,
|
Background: th.Palette.ContrastBg,
|
||||||
|
Foreground: th.Palette.ContrastFg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decorations provides window decorations.
|
// Layout a window with its title and action buttons.
|
||||||
type Decorations struct {
|
func (d *DecorationsStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||||
actions struct {
|
|
||||||
layout.List
|
|
||||||
clicks []widget.Clickable
|
|
||||||
move gesture.Drag
|
|
||||||
resize [8]struct {
|
|
||||||
gesture.Hover
|
|
||||||
gesture.Drag
|
|
||||||
}
|
|
||||||
}
|
|
||||||
actioned system.Action
|
|
||||||
path clip.Path
|
|
||||||
maximized bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Layout a window with the title and actions defined in DecorationsStyle.
|
|
||||||
func (d *DecorationsStyle) Layout(gtx layout.Context, title string) layout.Dimensions {
|
|
||||||
rec := op.Record(gtx.Ops)
|
rec := op.Record(gtx.Ops)
|
||||||
label := d.Title
|
|
||||||
label.Text = title
|
|
||||||
paint.ColorOp{Color: d.Foreground}.Add(gtx.Ops)
|
paint.ColorOp{Color: d.Foreground}.Add(gtx.Ops)
|
||||||
dims := d.Decorations.layoutDecorations(gtx, d.Actions, label.Layout)
|
dims := d.layoutDecorations(gtx)
|
||||||
decos := rec.Stop()
|
decos := rec.Stop()
|
||||||
r := clip.Rect{Max: dims.Size}
|
r := clip.Rect{Max: dims.Size}
|
||||||
paint.FillShape(gtx.Ops, d.Background, r.Op())
|
paint.FillShape(gtx.Ops, d.Background, r.Op())
|
||||||
decos.Add(gtx.Ops)
|
decos.Add(gtx.Ops)
|
||||||
d.Decorations.layoutResizing(gtx, d.Actions)
|
if !d.Decorations.Maximized() {
|
||||||
|
d.Decorations.LayoutResize(gtx, d.Actions)
|
||||||
|
}
|
||||||
return dims
|
return dims
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Decorations) layoutResizing(gtx layout.Context, actions system.Action) {
|
func (d *DecorationsStyle) layoutDecorations(gtx layout.Context) layout.Dimensions {
|
||||||
cs := gtx.Constraints.Max
|
|
||||||
wh := gtx.Px(unit.Dp(10))
|
|
||||||
s := []struct {
|
|
||||||
system.Action
|
|
||||||
image.Rectangle
|
|
||||||
}{
|
|
||||||
{system.ActionResizeNorth, image.Rect(0, 0, cs.X, wh)},
|
|
||||||
{system.ActionResizeSouth, image.Rect(0, cs.Y-wh, 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.ActionResizeNorthWest, image.Rect(0, 0, wh, wh)},
|
|
||||||
{system.ActionResizeNorthEast, image.Rect(cs.X-wh, 0, cs.X, wh)},
|
|
||||||
{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)},
|
|
||||||
}
|
|
||||||
for i, data := range s {
|
|
||||||
action := data.Action
|
|
||||||
if actions&action == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rsz := &d.actions.resize[i]
|
|
||||||
rsz.Events(gtx.Metric, gtx, gesture.Both)
|
|
||||||
if rsz.Drag.Dragging() {
|
|
||||||
d.actioned |= action
|
|
||||||
}
|
|
||||||
st := clip.Rect(data.Rectangle).Push(gtx.Ops)
|
|
||||||
if rsz.Hover.Hovered(gtx) {
|
|
||||||
pointer.CursorNameOp{Name: action.CursorName()}.Add(gtx.Ops)
|
|
||||||
}
|
|
||||||
rsz.Drag.Add(gtx.Ops)
|
|
||||||
pass := pointer.PassOp{}.Push(gtx.Ops)
|
|
||||||
rsz.Hover.Add(gtx.Ops)
|
|
||||||
pass.Pop()
|
|
||||||
st.Pop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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{
|
||||||
@@ -116,87 +60,49 @@ func (d *Decorations) layoutDecorations(gtx layout.Context, actions system.Actio
|
|||||||
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 {
|
||||||
dims := inset.Layout(gtx, title)
|
return d.Decorations.LayoutMove(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
if actions&system.ActionMove != 0 {
|
return inset.Layout(gtx, d.Title.Layout)
|
||||||
d.actions.move.Events(gtx.Metric, gtx, gesture.Both)
|
|
||||||
|
|
||||||
st := clip.Rect{Max: dims.Size}.Push(gtx.Ops)
|
|
||||||
d.actions.move.Add(gtx.Ops)
|
|
||||||
if d.actions.move.Pressed() {
|
|
||||||
d.actioned |= system.ActionMove
|
|
||||||
}
|
|
||||||
st.Pop()
|
|
||||||
}
|
|
||||||
return dims
|
|
||||||
}),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
// Remove the unmaximize action as it is taken care of by maximize.
|
|
||||||
actions := actions &^ system.ActionUnmaximize
|
|
||||||
an := bits.OnesCount(uint(actions))
|
|
||||||
if n := len(d.actions.clicks); n < an {
|
|
||||||
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 {
|
|
||||||
defer func() { action <<= 1 }()
|
|
||||||
for actions&action == 0 {
|
|
||||||
action <<= 1
|
|
||||||
}
|
|
||||||
click := &d.actions.clicks[idx]
|
|
||||||
if click.Clicked() {
|
|
||||||
if action == system.ActionMaximize {
|
|
||||||
if d.maximized {
|
|
||||||
d.maximized = false
|
|
||||||
d.actioned |= system.ActionUnmaximize
|
|
||||||
} else {
|
|
||||||
d.maximized = true
|
|
||||||
d.actioned |= system.ActionMaximize
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
d.actioned |= action
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
defer op.Offset(f32.Point{}).Push(gtx.Ops).Pop()
|
||||||
|
// Remove the unmaximize action as it is taken care of by maximize.
|
||||||
|
actions := d.Actions &^ system.ActionUnmaximize
|
||||||
|
var size image.Point
|
||||||
|
for a := system.Action(1); actions != 0; a <<= 1 {
|
||||||
|
if a&actions == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
actions &^= a
|
||||||
|
var w layout.Widget
|
||||||
|
switch a {
|
||||||
|
case system.ActionMinimize:
|
||||||
|
w = minimizeWindow
|
||||||
|
case system.ActionMaximize:
|
||||||
|
if d.Decorations.Maximized() {
|
||||||
|
w = maximizedWindow
|
||||||
|
} else {
|
||||||
|
w = maximizeWindow
|
||||||
|
}
|
||||||
|
case system.ActionClose:
|
||||||
|
w = closeWindow
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dims := d.Decorations.Clickable(a).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return inset.Layout(gtx, w)
|
||||||
|
})
|
||||||
|
size.X += dims.Size.X
|
||||||
|
if size.Y < dims.Size.Y {
|
||||||
|
size.Y = dims.Size.Y
|
||||||
|
}
|
||||||
|
op.Offset(f32.Point{X: float32(dims.Size.X)}).Add(gtx.Ops)
|
||||||
|
}
|
||||||
|
return layout.Dimensions{Size: size}
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform updates the decorations as if the specified actions were
|
|
||||||
// performed by the user.
|
|
||||||
func (d *Decorations) Perform(actions system.Action) {
|
|
||||||
if actions&system.ActionMaximize != 0 {
|
|
||||||
d.maximized = true
|
|
||||||
}
|
|
||||||
if actions&(system.ActionUnmaximize|system.ActionMinimize|system.ActionFullscreen) != 0 {
|
|
||||||
d.maximized = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actions returns the set of actions activated by the user.
|
|
||||||
func (d *Decorations) Actions() system.Action {
|
|
||||||
a := d.actioned
|
|
||||||
d.actioned = 0
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
winIconSize = unit.Dp(20)
|
winIconSize = unit.Dp(20)
|
||||||
winIconMargin = unit.Dp(4)
|
winIconMargin = unit.Dp(4)
|
||||||
|
|||||||
Reference in New Issue
Block a user