gioui.org@v0.6.1-0.20240506124620-7a9ce51988ce/widget/decorations.go (about)

     1  package widget
     2  
     3  import (
     4  	"fmt"
     5  	"math/bits"
     6  
     7  	"gioui.org/io/system"
     8  	"gioui.org/layout"
     9  	"gioui.org/op/clip"
    10  )
    11  
    12  // Decorations handles the states of window decorations.
    13  type Decorations struct {
    14  	clicks    map[int]*Clickable
    15  	maximized bool
    16  }
    17  
    18  // LayoutMove lays out the widget that makes a window movable.
    19  func (d *Decorations) LayoutMove(gtx layout.Context, w layout.Widget) layout.Dimensions {
    20  	dims := w(gtx)
    21  	defer clip.Rect{Max: dims.Size}.Push(gtx.Ops).Pop()
    22  	system.ActionInputOp(system.ActionMove).Add(gtx.Ops)
    23  	return dims
    24  }
    25  
    26  // Clickable returns the clickable for the given single action.
    27  func (d *Decorations) Clickable(action system.Action) *Clickable {
    28  	if bits.OnesCount(uint(action)) != 1 {
    29  		panic(fmt.Errorf("not a single action"))
    30  	}
    31  	idx := bits.TrailingZeros(uint(action))
    32  	click, found := d.clicks[idx]
    33  	if !found {
    34  		click = new(Clickable)
    35  		if d.clicks == nil {
    36  			d.clicks = make(map[int]*Clickable)
    37  		}
    38  		d.clicks[idx] = click
    39  	}
    40  	return click
    41  }
    42  
    43  // Perform updates the decorations as if the specified actions were
    44  // performed by the user.
    45  func (d *Decorations) Perform(actions system.Action) {
    46  	if actions&system.ActionMaximize != 0 {
    47  		d.maximized = true
    48  	}
    49  	if actions&(system.ActionUnmaximize|system.ActionMinimize|system.ActionFullscreen) != 0 {
    50  		d.maximized = false
    51  	}
    52  }
    53  
    54  // Update the state and return the set of actions activated by the user.
    55  func (d *Decorations) Update(gtx layout.Context) system.Action {
    56  	var actions system.Action
    57  	for idx, clk := range d.clicks {
    58  		if !clk.Clicked(gtx) {
    59  			continue
    60  		}
    61  		action := system.Action(1 << idx)
    62  		switch {
    63  		case action == system.ActionMaximize && d.maximized:
    64  			action = system.ActionUnmaximize
    65  		case action == system.ActionUnmaximize && !d.maximized:
    66  			action = system.ActionMaximize
    67  		}
    68  		switch action {
    69  		case system.ActionMaximize, system.ActionUnmaximize:
    70  			d.maximized = !d.maximized
    71  		}
    72  		actions |= action
    73  	}
    74  	return actions
    75  }
    76  
    77  // Maximized returns whether the window is maximized.
    78  func (d *Decorations) Maximized() bool {
    79  	return d.maximized
    80  }