mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 18:05:35 +00:00
app,io/system,layout: [API] move FrameEvent and Insets to package app
In the early days of Gio, FrameEvent was part of package app. It was moved to package system to enable layout.NewContext be a convenient short-hand for constructing a layout. However, it seems the better design to leave FrameEvent (and Insets) in package app, and move layout.NewContext there as well. More importantly, the move allows us to replace the event.Queue interface with a concrete type. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+80
-6
@@ -3,9 +3,16 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gioui.org/io/event"
|
||||||
|
"gioui.org/layout"
|
||||||
|
"gioui.org/op"
|
||||||
|
"gioui.org/unit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// extraArgs contains extra arguments to append to
|
// extraArgs contains extra arguments to append to
|
||||||
@@ -30,13 +37,68 @@ var extraArgs string
|
|||||||
// is not supported. Default value of ID is filepath.Base(os.Args[0]).
|
// is not supported. Default value of ID is filepath.Base(os.Args[0]).
|
||||||
var ID = ""
|
var ID = ""
|
||||||
|
|
||||||
func init() {
|
// A FrameEvent requests a new frame in the form of a list of
|
||||||
if extraArgs != "" {
|
// operations that describes what to display and how to handle
|
||||||
args := strings.Split(extraArgs, "|")
|
// input.
|
||||||
os.Args = append(os.Args, args...)
|
type FrameEvent struct {
|
||||||
|
// Now is the current animation. Use Now instead of time.Now to
|
||||||
|
// synchronize animation and to avoid the time.Now call overhead.
|
||||||
|
Now time.Time
|
||||||
|
// Metric converts device independent dp and sp to device pixels.
|
||||||
|
Metric unit.Metric
|
||||||
|
// Size is the dimensions of the window.
|
||||||
|
Size image.Point
|
||||||
|
// Insets represent the space occupied by system decorations and controls.
|
||||||
|
Insets Insets
|
||||||
|
// Frame completes the FrameEvent by drawing the graphical operations
|
||||||
|
// from ops into the window.
|
||||||
|
Frame func(frame *op.Ops)
|
||||||
|
// Queue supplies the events for event handlers.
|
||||||
|
Queue event.Queue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insets is the space taken up by
|
||||||
|
// system decoration such as translucent
|
||||||
|
// system bars and software keyboards.
|
||||||
|
type Insets struct {
|
||||||
|
// Values are in pixels.
|
||||||
|
Top, Bottom, Left, Right unit.Dp
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContext is a shorthand for
|
||||||
|
//
|
||||||
|
// layout.Context{
|
||||||
|
// Ops: ops,
|
||||||
|
// Now: e.Now,
|
||||||
|
// Queue: e.Queue,
|
||||||
|
// Config: e.Config,
|
||||||
|
// Constraints: layout.Exact(e.Size),
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// NewContext calls ops.Reset and adjusts ops for e.Insets.
|
||||||
|
func NewContext(ops *op.Ops, e FrameEvent) layout.Context {
|
||||||
|
ops.Reset()
|
||||||
|
|
||||||
|
size := e.Size
|
||||||
|
|
||||||
|
if e.Insets != (Insets{}) {
|
||||||
|
left := e.Metric.Dp(e.Insets.Left)
|
||||||
|
top := e.Metric.Dp(e.Insets.Top)
|
||||||
|
op.Offset(image.Point{
|
||||||
|
X: left,
|
||||||
|
Y: top,
|
||||||
|
}).Add(ops)
|
||||||
|
|
||||||
|
size.X -= left + e.Metric.Dp(e.Insets.Right)
|
||||||
|
size.Y -= top + e.Metric.Dp(e.Insets.Bottom)
|
||||||
}
|
}
|
||||||
if ID == "" {
|
|
||||||
ID = filepath.Base(os.Args[0])
|
return layout.Context{
|
||||||
|
Ops: ops,
|
||||||
|
Now: e.Now,
|
||||||
|
Queue: e.Queue,
|
||||||
|
Metric: e.Metric,
|
||||||
|
Constraints: layout.Exact(size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,3 +125,15 @@ func DataDir() (string, error) {
|
|||||||
func Main() {
|
func Main() {
|
||||||
osMain()
|
osMain()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (FrameEvent) ImplementsEvent() {}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if extraArgs != "" {
|
||||||
|
args := strings.Split(extraArgs, "|")
|
||||||
|
os.Args = append(os.Args, args...)
|
||||||
|
}
|
||||||
|
if ID == "" {
|
||||||
|
ID = filepath.Base(os.Args[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1
-3
@@ -17,12 +17,10 @@ FrameEvent that prompts an update of the window contents.
|
|||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
import "gioui.org/unit"
|
|
||||||
|
|
||||||
w := app.NewWindow()
|
w := app.NewWindow()
|
||||||
for {
|
for {
|
||||||
e := w.NextEvent()
|
e := w.NextEvent()
|
||||||
if e, ok := e.(system.FrameEvent); ok {
|
if e, ok := e.(app.FrameEvent); ok {
|
||||||
ops.Reset()
|
ops.Reset()
|
||||||
// Add operations to ops.
|
// Add operations to ops.
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func (o Orientation) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type frameEvent struct {
|
type frameEvent struct {
|
||||||
system.FrameEvent
|
FrameEvent
|
||||||
|
|
||||||
Sync bool
|
Sync bool
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -836,14 +836,14 @@ func (w *window) draw(env *C.JNIEnv, sync bool) {
|
|||||||
const inchPrDp = 1.0 / 160
|
const inchPrDp = 1.0 / 160
|
||||||
ppdp := float32(w.dpi) * inchPrDp
|
ppdp := float32(w.dpi) * inchPrDp
|
||||||
dppp := unit.Dp(1.0 / ppdp)
|
dppp := unit.Dp(1.0 / ppdp)
|
||||||
insets := system.Insets{
|
insets := Insets{
|
||||||
Top: unit.Dp(w.insets.top) * dppp,
|
Top: unit.Dp(w.insets.top) * dppp,
|
||||||
Bottom: unit.Dp(w.insets.bottom) * dppp,
|
Bottom: unit.Dp(w.insets.bottom) * dppp,
|
||||||
Left: unit.Dp(w.insets.left) * dppp,
|
Left: unit.Dp(w.insets.left) * dppp,
|
||||||
Right: unit.Dp(w.insets.right) * dppp,
|
Right: unit.Dp(w.insets.right) * dppp,
|
||||||
}
|
}
|
||||||
w.callbacks.Event(frameEvent{
|
w.callbacks.Event(frameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
Size: w.config.Size,
|
Size: w.config.Size,
|
||||||
Insets: insets,
|
Insets: insets,
|
||||||
|
|||||||
+2
-2
@@ -156,13 +156,13 @@ func (w *window) draw(sync bool) {
|
|||||||
}
|
}
|
||||||
dppp := unit.Dp(1. / m.PxPerDp)
|
dppp := unit.Dp(1. / m.PxPerDp)
|
||||||
w.w.Event(frameEvent{
|
w.w.Event(frameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
Size: image.Point{
|
Size: image.Point{
|
||||||
X: int(params.width + .5),
|
X: int(params.width + .5),
|
||||||
Y: int(params.height + .5),
|
Y: int(params.height + .5),
|
||||||
},
|
},
|
||||||
Insets: system.Insets{
|
Insets: Insets{
|
||||||
Top: unit.Dp(params.top) * dppp,
|
Top: unit.Dp(params.top) * dppp,
|
||||||
Bottom: unit.Dp(params.bottom) * dppp,
|
Bottom: unit.Dp(params.bottom) * dppp,
|
||||||
Left: unit.Dp(params.left) * dppp,
|
Left: unit.Dp(params.left) * dppp,
|
||||||
|
|||||||
+3
-3
@@ -666,7 +666,7 @@ func (w *window) draw(sync bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.w.Event(frameEvent{
|
w.w.Event(frameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
Size: size,
|
Size: size,
|
||||||
Insets: insets,
|
Insets: insets,
|
||||||
@@ -676,10 +676,10 @@ func (w *window) draw(sync bool) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) getConfig() (image.Point, system.Insets, unit.Metric) {
|
func (w *window) getConfig() (image.Point, Insets, unit.Metric) {
|
||||||
invscale := unit.Dp(1. / w.scale)
|
invscale := unit.Dp(1. / w.scale)
|
||||||
return image.Pt(w.config.Size.X, w.config.Size.Y),
|
return image.Pt(w.config.Size.X, w.config.Size.Y),
|
||||||
system.Insets{
|
Insets{
|
||||||
Bottom: unit.Dp(w.inset.Y) * invscale,
|
Bottom: unit.Dp(w.inset.Y) * invscale,
|
||||||
Right: unit.Dp(w.inset.X) * invscale,
|
Right: unit.Dp(w.inset.X) * invscale,
|
||||||
}, unit.Metric{
|
}, unit.Metric{
|
||||||
|
|||||||
+1
-1
@@ -777,7 +777,7 @@ func (w *window) draw() {
|
|||||||
cfg := configFor(w.scale)
|
cfg := configFor(w.scale)
|
||||||
w.setStage(system.StageRunning)
|
w.setStage(system.StageRunning)
|
||||||
w.w.Event(frameEvent{
|
w.w.Event(frameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
Size: w.config.Size,
|
Size: w.config.Size,
|
||||||
Metric: cfg,
|
Metric: cfg,
|
||||||
|
|||||||
+1
-1
@@ -1712,7 +1712,7 @@ func (w *window) draw() {
|
|||||||
C.wl_callback_add_listener(w.lastFrameCallback, &C.gio_callback_listener, unsafe.Pointer(w.surf))
|
C.wl_callback_add_listener(w.lastFrameCallback, &C.gio_callback_listener, unsafe.Pointer(w.surf))
|
||||||
}
|
}
|
||||||
w.w.Event(frameEvent{
|
w.w.Event(frameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
Size: w.config.Size,
|
Size: w.config.Size,
|
||||||
Metric: cfg,
|
Metric: cfg,
|
||||||
|
|||||||
+1
-1
@@ -621,7 +621,7 @@ func (w *window) draw(sync bool) {
|
|||||||
dpi := windows.GetWindowDPI(w.hwnd)
|
dpi := windows.GetWindowDPI(w.hwnd)
|
||||||
cfg := configForDPI(dpi)
|
cfg := configForDPI(dpi)
|
||||||
w.w.Event(frameEvent{
|
w.w.Event(frameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
Size: w.config.Size,
|
Size: w.config.Size,
|
||||||
Metric: cfg,
|
Metric: cfg,
|
||||||
|
|||||||
+1
-1
@@ -458,7 +458,7 @@ loop:
|
|||||||
|
|
||||||
if (anim || syn) && w.config.Size.X != 0 && w.config.Size.Y != 0 {
|
if (anim || syn) && w.config.Size.X != 0 && w.config.Size.Y != 0 {
|
||||||
w.w.Event(frameEvent{
|
w.w.Event(frameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
Size: w.config.Size,
|
Size: w.config.Size,
|
||||||
Metric: w.metric,
|
Metric: w.metric,
|
||||||
|
|||||||
+1
-1
@@ -994,7 +994,7 @@ func (w *Window) fallbackDecorate() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// decorate the window if enabled and returns the corresponding Insets.
|
// decorate the window if enabled and returns the corresponding Insets.
|
||||||
func (w *Window) decorate(d driver, e system.FrameEvent, o *op.Ops) (size, offset image.Point) {
|
func (w *Window) decorate(d driver, e FrameEvent, o *op.Ops) (size, offset image.Point) {
|
||||||
if !w.fallbackDecorate() {
|
if !w.fallbackDecorate() {
|
||||||
return e.Size, image.Pt(0, 0)
|
return e.Size, image.Pt(0, 0)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-41
@@ -4,35 +4,6 @@
|
|||||||
// program level.
|
// program level.
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
|
||||||
"image"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gioui.org/io/event"
|
|
||||||
"gioui.org/op"
|
|
||||||
"gioui.org/unit"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A FrameEvent requests a new frame in the form of a list of
|
|
||||||
// operations that describes what to display and how to handle
|
|
||||||
// input.
|
|
||||||
type FrameEvent struct {
|
|
||||||
// Now is the current animation. Use Now instead of time.Now to
|
|
||||||
// synchronize animation and to avoid the time.Now call overhead.
|
|
||||||
Now time.Time
|
|
||||||
// Metric converts device independent dp and sp to device pixels.
|
|
||||||
Metric unit.Metric
|
|
||||||
// Size is the dimensions of the window.
|
|
||||||
Size image.Point
|
|
||||||
// Insets represent the space occupied by system decorations and controls.
|
|
||||||
Insets Insets
|
|
||||||
// Frame completes the FrameEvent by drawing the graphical operations
|
|
||||||
// from ops into the window.
|
|
||||||
Frame func(frame *op.Ops)
|
|
||||||
// Queue supplies the events for event handlers.
|
|
||||||
Queue event.Queue
|
|
||||||
}
|
|
||||||
|
|
||||||
// DestroyEvent is the last event sent through
|
// DestroyEvent is the last event sent through
|
||||||
// a window event channel.
|
// a window event channel.
|
||||||
type DestroyEvent struct {
|
type DestroyEvent struct {
|
||||||
@@ -41,14 +12,6 @@ type DestroyEvent struct {
|
|||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insets is the space taken up by
|
|
||||||
// system decoration such as translucent
|
|
||||||
// system bars and software keyboards.
|
|
||||||
type Insets struct {
|
|
||||||
// Values are in pixels.
|
|
||||||
Top, Bottom, Left, Right unit.Dp
|
|
||||||
}
|
|
||||||
|
|
||||||
// A StageEvent is generated whenever the stage of a
|
// A StageEvent is generated whenever the stage of a
|
||||||
// Window changes.
|
// Window changes.
|
||||||
type StageEvent struct {
|
type StageEvent struct {
|
||||||
@@ -60,13 +23,13 @@ type Stage uint8
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// StagePaused is the stage for windows that have no on-screen representation.
|
// StagePaused is the stage for windows that have no on-screen representation.
|
||||||
// Paused windows don't receive FrameEvent.
|
// Paused windows don't receive frames.
|
||||||
StagePaused Stage = iota
|
StagePaused Stage = iota
|
||||||
// StageInactive is the stage for windows that are visible, but not active.
|
// StageInactive is the stage for windows that are visible, but not active.
|
||||||
// Inactive windows receive FrameEvent.
|
// Inactive windows receive frames.
|
||||||
StageInactive
|
StageInactive
|
||||||
// StageRunning is for active and visible Windows.
|
// StageRunning is for active and visible Windows.
|
||||||
// Running windows receive FrameEvent.
|
// Running windows receive frames.
|
||||||
StageRunning
|
StageRunning
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -84,6 +47,5 @@ func (l Stage) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (FrameEvent) ImplementsEvent() {}
|
|
||||||
func (StageEvent) ImplementsEvent() {}
|
func (StageEvent) ImplementsEvent() {}
|
||||||
func (DestroyEvent) ImplementsEvent() {}
|
func (DestroyEvent) ImplementsEvent() {}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
package layout
|
package layout
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gioui.org/io/event"
|
"gioui.org/io/event"
|
||||||
@@ -35,43 +34,6 @@ type Context struct {
|
|||||||
*op.Ops
|
*op.Ops
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContext is a shorthand for
|
|
||||||
//
|
|
||||||
// Context{
|
|
||||||
// Ops: ops,
|
|
||||||
// Now: e.Now,
|
|
||||||
// Queue: e.Queue,
|
|
||||||
// Config: e.Config,
|
|
||||||
// Constraints: Exact(e.Size),
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// NewContext calls ops.Reset and adjusts ops for e.Insets.
|
|
||||||
func NewContext(ops *op.Ops, e system.FrameEvent) Context {
|
|
||||||
ops.Reset()
|
|
||||||
|
|
||||||
size := e.Size
|
|
||||||
|
|
||||||
if e.Insets != (system.Insets{}) {
|
|
||||||
left := e.Metric.Dp(e.Insets.Left)
|
|
||||||
top := e.Metric.Dp(e.Insets.Top)
|
|
||||||
op.Offset(image.Point{
|
|
||||||
X: left,
|
|
||||||
Y: top,
|
|
||||||
}).Add(ops)
|
|
||||||
|
|
||||||
size.X -= left + e.Metric.Dp(e.Insets.Right)
|
|
||||||
size.Y -= top + e.Metric.Dp(e.Insets.Bottom)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Context{
|
|
||||||
Ops: ops,
|
|
||||||
Now: e.Now,
|
|
||||||
Queue: e.Queue,
|
|
||||||
Metric: e.Metric,
|
|
||||||
Constraints: Exact(size),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dp converts v to pixels.
|
// Dp converts v to pixels.
|
||||||
func (c Context) Dp(v unit.Dp) int {
|
func (c Context) Dp(v unit.Dp) int {
|
||||||
return c.Metric.Dp(v)
|
return c.Metric.Dp(v)
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"gioui.org/app"
|
||||||
"gioui.org/io/key"
|
"gioui.org/io/key"
|
||||||
"gioui.org/io/router"
|
"gioui.org/io/router"
|
||||||
"gioui.org/io/system"
|
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
@@ -21,7 +21,7 @@ func TestClickable(t *testing.T) {
|
|||||||
b1 widget.Clickable
|
b1 widget.Clickable
|
||||||
b2 widget.Clickable
|
b2 widget.Clickable
|
||||||
)
|
)
|
||||||
gtx := layout.NewContext(&ops, system.FrameEvent{Queue: &r})
|
gtx := app.NewContext(&ops, app.FrameEvent{Queue: &r})
|
||||||
layout := func() {
|
layout := func() {
|
||||||
b1.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
b1.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
return layout.Dimensions{Size: image.Pt(100, 100)}
|
return layout.Dimensions{Size: image.Pt(100, 100)}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gioui.org/io/system"
|
"gioui.org/app"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
"gioui.org/unit"
|
"gioui.org/unit"
|
||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
func TestListAnchorStrategies(t *testing.T) {
|
func TestListAnchorStrategies(t *testing.T) {
|
||||||
var ops op.Ops
|
var ops op.Ops
|
||||||
gtx := layout.NewContext(&ops, system.FrameEvent{
|
gtx := app.NewContext(&ops, app.FrameEvent{
|
||||||
Metric: unit.Metric{
|
Metric: unit.Metric{
|
||||||
PxPerDp: 1,
|
PxPerDp: 1,
|
||||||
PxPerSp: 1,
|
PxPerSp: 1,
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"gioui.org/app"
|
||||||
"gioui.org/f32"
|
"gioui.org/f32"
|
||||||
"gioui.org/io/pointer"
|
"gioui.org/io/pointer"
|
||||||
"gioui.org/io/router"
|
"gioui.org/io/router"
|
||||||
"gioui.org/io/semantic"
|
"gioui.org/io/semantic"
|
||||||
"gioui.org/io/system"
|
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
"gioui.org/widget"
|
"gioui.org/widget"
|
||||||
@@ -22,7 +22,7 @@ func TestBool(t *testing.T) {
|
|||||||
r router.Router
|
r router.Router
|
||||||
b widget.Bool
|
b widget.Bool
|
||||||
)
|
)
|
||||||
gtx := layout.NewContext(&ops, system.FrameEvent{Queue: &r})
|
gtx := app.NewContext(&ops, app.FrameEvent{Queue: &r})
|
||||||
layout := func() {
|
layout := func() {
|
||||||
b.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
b.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
semantic.CheckBox.Add(gtx.Ops)
|
semantic.CheckBox.Add(gtx.Ops)
|
||||||
|
|||||||
Reference in New Issue
Block a user