mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-03 08:25:34 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 718be79d9e | |||
| 0073e1a167 | |||
| 32ecec5538 | |||
| 6eb33b8a56 | |||
| 4617526e12 | |||
| dbc7a900bd | |||
| fb3ae95b28 | |||
| c458eb30f0 | |||
| d96c954769 | |||
| f39245df99 | |||
| 8097df9930 | |||
| fc6e51deba | |||
| 5fa94ff67b | |||
| 23b6f06e3e |
+16
-6
@@ -8,16 +8,21 @@ packages:
|
|||||||
- libxml2-dev
|
- libxml2-dev
|
||||||
- libssl-dev
|
- libssl-dev
|
||||||
- libz-dev
|
- libz-dev
|
||||||
- llvm-dev # for cctools
|
- llvm-dev # cctools
|
||||||
- uuid-dev ## for cctools
|
- uuid-dev # cctools
|
||||||
|
- ninja-build # cctools
|
||||||
|
- systemtap-sdt-dev # cctools
|
||||||
|
- libbsd-dev # cctools
|
||||||
|
- linux-libc-dev # cctools
|
||||||
- libplist-utils # for gogio
|
- libplist-utils # for gogio
|
||||||
sources:
|
sources:
|
||||||
- https://git.sr.ht/~eliasnaur/applesdks
|
- https://git.sr.ht/~eliasnaur/applesdks
|
||||||
- https://git.sr.ht/~eliasnaur/gio
|
- https://git.sr.ht/~eliasnaur/gio
|
||||||
- https://git.sr.ht/~eliasnaur/giouiorg
|
- https://git.sr.ht/~eliasnaur/giouiorg
|
||||||
- https://github.com/tpoechtrager/cctools-port.git
|
- https://github.com/tpoechtrager/cctools-port
|
||||||
- https://github.com/tpoechtrager/apple-libtapi.git
|
- https://github.com/tpoechtrager/apple-libtapi
|
||||||
- https://github.com/mackyle/xar.git
|
- https://github.com/tpoechtrager/apple-libdispatch
|
||||||
|
- https://github.com/mackyle/xar
|
||||||
environment:
|
environment:
|
||||||
APPLE_TOOLCHAIN_ROOT: /home/build/appletools
|
APPLE_TOOLCHAIN_ROOT: /home/build/appletools
|
||||||
PATH: /home/build/sdk/go/bin:/home/build/go/bin:/usr/bin
|
PATH: /home/build/sdk/go/bin:/home/build/go/bin:/usr/bin
|
||||||
@@ -42,6 +47,11 @@ tasks:
|
|||||||
- install_appletoolchain: |
|
- install_appletoolchain: |
|
||||||
cd giouiorg
|
cd giouiorg
|
||||||
go build -o $APPLE_TOOLCHAIN_ROOT/tools ./cmd/appletoolchain
|
go build -o $APPLE_TOOLCHAIN_ROOT/tools ./cmd/appletoolchain
|
||||||
|
- build_libdispatch: |
|
||||||
|
cd apple-libdispatch
|
||||||
|
cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_INSTALL_PREFIX=$APPLE_TOOLCHAIN_ROOT/libdispatch .
|
||||||
|
ninja
|
||||||
|
ninja install
|
||||||
- build_xar: |
|
- build_xar: |
|
||||||
cd xar/xar
|
cd xar/xar
|
||||||
ac_cv_lib_crypto_OpenSSL_add_all_ciphers=yes CC=clang ./autogen.sh --prefix=/usr
|
ac_cv_lib_crypto_OpenSSL_add_all_ciphers=yes CC=clang ./autogen.sh --prefix=/usr
|
||||||
@@ -53,7 +63,7 @@ tasks:
|
|||||||
./install.sh
|
./install.sh
|
||||||
- build_cctools: |
|
- build_cctools: |
|
||||||
cd cctools-port/cctools
|
cd cctools-port/cctools
|
||||||
./configure --prefix $APPLE_TOOLCHAIN_ROOT/toolchain --with-libtapi=$APPLE_TOOLCHAIN_ROOT/libtapi --target=x86_64-apple-darwin19
|
./configure --target=x86_64-apple-darwin19 --prefix $APPLE_TOOLCHAIN_ROOT/toolchain --with-libtapi=$APPLE_TOOLCHAIN_ROOT/libtapi --with-libdispatch=$APPLE_TOOLCHAIN_ROOT/libdispatch --with-libblocksruntime=$APPLE_TOOLCHAIN_ROOT/libdispatch
|
||||||
make install
|
make install
|
||||||
- test_macos: |
|
- test_macos: |
|
||||||
cd gio
|
cd gio
|
||||||
|
|||||||
@@ -60,10 +60,10 @@ func (c *d3d11Context) RenderTarget() (gpu.RenderTarget, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *d3d11Context) Present() error {
|
func (c *d3d11Context) Present() error {
|
||||||
err := c.swchain.Present(1, 0)
|
return wrapErr(c.swchain.Present(1, 0))
|
||||||
if err == nil {
|
}
|
||||||
return nil
|
|
||||||
}
|
func wrapErr(err error) error {
|
||||||
if err, ok := err.(d3d11.ErrorCode); ok {
|
if err, ok := err.(d3d11.ErrorCode); ok {
|
||||||
switch err.Code {
|
switch err.Code {
|
||||||
case d3d11.DXGI_STATUS_OCCLUDED:
|
case d3d11.DXGI_STATUS_OCCLUDED:
|
||||||
@@ -84,7 +84,7 @@ func (c *d3d11Context) Refresh() error {
|
|||||||
}
|
}
|
||||||
c.releaseFBO()
|
c.releaseFBO()
|
||||||
if err := c.swchain.ResizeBuffers(0, 0, 0, d3d11.DXGI_FORMAT_UNKNOWN, 0); err != nil {
|
if err := c.swchain.ResizeBuffers(0, 0, 0, d3d11.DXGI_FORMAT_UNKNOWN, 0); err != nil {
|
||||||
return err
|
return wrapErr(err)
|
||||||
}
|
}
|
||||||
c.width = width
|
c.width = width
|
||||||
c.height = height
|
c.height = height
|
||||||
|
|||||||
@@ -192,6 +192,10 @@ static CFTypeRef windowForView(CFTypeRef viewRef) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void raiseWindow(CFTypeRef windowRef) {
|
static void raiseWindow(CFTypeRef windowRef) {
|
||||||
|
NSRunningApplication *currentApp = [NSRunningApplication currentApplication];
|
||||||
|
if (![currentApp isActive]) {
|
||||||
|
[currentApp activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
|
||||||
|
}
|
||||||
NSWindow* window = (__bridge NSWindow *)windowRef;
|
NSWindow* window = (__bridge NSWindow *)windowRef;
|
||||||
[window makeKeyAndOrderFront:nil];
|
[window makeKeyAndOrderFront:nil];
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -721,11 +721,12 @@ func (w *window) Configure(options []Option) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Fullscreen:
|
case Fullscreen:
|
||||||
|
swpStyle |= windows.SWP_NOMOVE | windows.SWP_NOSIZE
|
||||||
mi := windows.GetMonitorInfo(w.hwnd)
|
mi := windows.GetMonitorInfo(w.hwnd)
|
||||||
x, y = mi.Monitor.Left, mi.Monitor.Top
|
x, y = mi.Monitor.Left, mi.Monitor.Top
|
||||||
width = mi.Monitor.Right - mi.Monitor.Left
|
width = mi.Monitor.Right - mi.Monitor.Left
|
||||||
height = mi.Monitor.Bottom - mi.Monitor.Top
|
height = mi.Monitor.Bottom - mi.Monitor.Top
|
||||||
showMode = windows.SW_SHOW
|
showMode = windows.SW_SHOWMAXIMIZED
|
||||||
}
|
}
|
||||||
windows.SetWindowLong(w.hwnd, windows.GWL_STYLE, style)
|
windows.SetWindowLong(w.hwnd, windows.GWL_STYLE, style)
|
||||||
windows.SetWindowPos(w.hwnd, 0, x, y, width, height, swpStyle)
|
windows.SetWindowPos(w.hwnd, 0, x, y, width, height, swpStyle)
|
||||||
|
|||||||
+2
-1
@@ -904,6 +904,7 @@ func (w *Window) processEvent(d driver, e event.Event) bool {
|
|||||||
w.decorations.Config = e2.Config
|
w.decorations.Config = e2.Config
|
||||||
e2.Config = w.effectiveConfig()
|
e2.Config = w.effectiveConfig()
|
||||||
w.out <- e2
|
w.out <- e2
|
||||||
|
case wakeupEvent:
|
||||||
case event.Event:
|
case event.Event:
|
||||||
handled := w.queue.q.Queue(e2)
|
handled := w.queue.q.Queue(e2)
|
||||||
if e, ok := e.(key.Event); ok && !handled {
|
if e, ok := e.(key.Event); ok && !handled {
|
||||||
@@ -1035,9 +1036,9 @@ func (w *Window) decorate(d driver, e system.FrameEvent, o *op.Ops) (size, offse
|
|||||||
Metric: e.Metric,
|
Metric: e.Metric,
|
||||||
Constraints: layout.Exact(e.Size),
|
Constraints: layout.Exact(e.Size),
|
||||||
}
|
}
|
||||||
style.Layout(gtx)
|
|
||||||
// Update the window based on the actions on the decorations.
|
// Update the window based on the actions on the decorations.
|
||||||
w.Perform(deco.Update(gtx))
|
w.Perform(deco.Update(gtx))
|
||||||
|
style.Layout(gtx)
|
||||||
// Offset to place the frame content below the decorations.
|
// Offset to place the frame content below the decorations.
|
||||||
decoHeight := gtx.Dp(w.decorations.Config.decoHeight)
|
decoHeight := gtx.Dp(w.decorations.Config.decoHeight)
|
||||||
if w.decorations.currentHeight != decoHeight {
|
if w.decorations.currentHeight != decoHeight {
|
||||||
|
|||||||
+4
-4
@@ -446,13 +446,13 @@ func (a Axis) String() string {
|
|||||||
func (ct ClickKind) String() string {
|
func (ct ClickKind) String() string {
|
||||||
switch ct {
|
switch ct {
|
||||||
case KindPress:
|
case KindPress:
|
||||||
return "TypePress"
|
return "KindPress"
|
||||||
case KindClick:
|
case KindClick:
|
||||||
return "TypeClick"
|
return "KindClick"
|
||||||
case KindCancel:
|
case KindCancel:
|
||||||
return "TypeCancel"
|
return "KindCancel"
|
||||||
default:
|
default:
|
||||||
panic("invalid ClickType")
|
panic("invalid ClickKind")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+32
-3
@@ -186,10 +186,16 @@ type material struct {
|
|||||||
uvTrans f32.Affine2D
|
uvTrans f32.Affine2D
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
filterLinear = 0
|
||||||
|
filterNearest = 1
|
||||||
|
)
|
||||||
|
|
||||||
// imageOpData is the shadow of paint.ImageOp.
|
// imageOpData is the shadow of paint.ImageOp.
|
||||||
type imageOpData struct {
|
type imageOpData struct {
|
||||||
src *image.RGBA
|
src *image.RGBA
|
||||||
handle interface{}
|
handle interface{}
|
||||||
|
filter byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type linearGradientOpData struct {
|
type linearGradientOpData struct {
|
||||||
@@ -207,6 +213,7 @@ func decodeImageOp(data []byte, refs []interface{}) imageOpData {
|
|||||||
return imageOpData{
|
return imageOpData{
|
||||||
src: refs[0].(*image.RGBA),
|
src: refs[0].(*image.RGBA),
|
||||||
handle: handle,
|
handle: handle,
|
||||||
|
filter: data[1],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,19 +461,41 @@ func (g *gpu) Profile() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *renderer) texHandle(cache *resourceCache, data imageOpData) driver.Texture {
|
func (r *renderer) texHandle(cache *resourceCache, data imageOpData) driver.Texture {
|
||||||
|
type cachekey struct {
|
||||||
|
filter byte
|
||||||
|
handle any
|
||||||
|
}
|
||||||
|
key := cachekey{
|
||||||
|
filter: data.filter,
|
||||||
|
handle: data.handle,
|
||||||
|
}
|
||||||
|
|
||||||
var tex *texture
|
var tex *texture
|
||||||
t, exists := cache.get(data.handle)
|
t, exists := cache.get(key)
|
||||||
if !exists {
|
if !exists {
|
||||||
t = &texture{
|
t = &texture{
|
||||||
src: data.src,
|
src: data.src,
|
||||||
}
|
}
|
||||||
cache.put(data.handle, t)
|
cache.put(key, t)
|
||||||
}
|
}
|
||||||
tex = t.(*texture)
|
tex = t.(*texture)
|
||||||
if tex.tex != nil {
|
if tex.tex != nil {
|
||||||
return tex.tex
|
return tex.tex
|
||||||
}
|
}
|
||||||
handle, err := r.ctx.NewTexture(driver.TextureFormatSRGBA, data.src.Bounds().Dx(), data.src.Bounds().Dy(), driver.FilterLinearMipmapLinear, driver.FilterLinear, driver.BufferBindingTexture)
|
|
||||||
|
var minFilter, magFilter driver.TextureFilter
|
||||||
|
switch data.filter {
|
||||||
|
case filterLinear:
|
||||||
|
minFilter, magFilter = driver.FilterLinearMipmapLinear, driver.FilterLinear
|
||||||
|
case filterNearest:
|
||||||
|
minFilter, magFilter = driver.FilterNearest, driver.FilterNearest
|
||||||
|
}
|
||||||
|
|
||||||
|
handle, err := r.ctx.NewTexture(driver.TextureFormatSRGBA,
|
||||||
|
data.src.Bounds().Dx(), data.src.Bounds().Dy(),
|
||||||
|
minFilter, magFilter,
|
||||||
|
driver.BufferBindingTexture,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 379 B |
@@ -359,6 +359,73 @@ func TestImageRGBA(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImageRGBA_ScaleLinear(t *testing.T) {
|
||||||
|
run(t, func(o *op.Ops) {
|
||||||
|
w := newWindow(t, 128, 128)
|
||||||
|
defer clip.Rect{Max: image.Pt(128, 128)}.Push(o).Pop()
|
||||||
|
op.Affine(f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(64, 64))).Add(o)
|
||||||
|
|
||||||
|
im := image.NewRGBA(image.Rect(0, 0, 2, 2))
|
||||||
|
im.Set(0, 0, colornames.Red)
|
||||||
|
im.Set(1, 0, colornames.Green)
|
||||||
|
im.Set(0, 1, colornames.White)
|
||||||
|
im.Set(1, 1, colornames.Black)
|
||||||
|
|
||||||
|
op := paint.NewImageOp(im)
|
||||||
|
op.Filter = paint.FilterLinear
|
||||||
|
op.Add(o)
|
||||||
|
|
||||||
|
paint.PaintOp{}.Add(o)
|
||||||
|
|
||||||
|
if err := w.Frame(o); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}, func(r result) {
|
||||||
|
r.expect(0, 0, colornames.Red)
|
||||||
|
r.expect(8, 8, colornames.Red)
|
||||||
|
|
||||||
|
// TODO: this currently seems to do srgb scaling
|
||||||
|
// instead of linear rgb scaling,
|
||||||
|
r.expect(64-4, 0, color.RGBA{R: 197, G: 87, B: 0, A: 255})
|
||||||
|
r.expect(64+4, 0, color.RGBA{R: 175, G: 98, B: 0, A: 255})
|
||||||
|
|
||||||
|
r.expect(127, 0, colornames.Green)
|
||||||
|
r.expect(127-8, 8, colornames.Green)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImageRGBA_ScaleNearest(t *testing.T) {
|
||||||
|
run(t, func(o *op.Ops) {
|
||||||
|
w := newWindow(t, 128, 128)
|
||||||
|
op.Affine(f32.Affine2D{}.Scale(f32.Point{}, f32.Pt(64, 64))).Add(o)
|
||||||
|
|
||||||
|
im := image.NewRGBA(image.Rect(0, 0, 2, 2))
|
||||||
|
im.Set(0, 0, colornames.Red)
|
||||||
|
im.Set(1, 0, colornames.Green)
|
||||||
|
im.Set(0, 1, colornames.White)
|
||||||
|
im.Set(1, 1, colornames.Black)
|
||||||
|
|
||||||
|
op := paint.NewImageOp(im)
|
||||||
|
op.Filter = paint.FilterNearest
|
||||||
|
op.Add(o)
|
||||||
|
|
||||||
|
paint.PaintOp{}.Add(o)
|
||||||
|
|
||||||
|
if err := w.Frame(o); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}, func(r result) {
|
||||||
|
r.expect(0, 0, colornames.Red)
|
||||||
|
r.expect(8, 8, colornames.Red)
|
||||||
|
|
||||||
|
r.expect(64-4, 0, colornames.Red)
|
||||||
|
r.expect(64+4, 0, colornames.Green)
|
||||||
|
|
||||||
|
r.expect(127, 0, colornames.Green)
|
||||||
|
r.expect(127-8, 8, colornames.Green)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestGapsInPath(t *testing.T) {
|
func TestGapsInPath(t *testing.T) {
|
||||||
ops := new(op.Ops)
|
ops := new(op.Ops)
|
||||||
var p clip.Path
|
var p clip.Path
|
||||||
|
|||||||
+1
-1
@@ -142,7 +142,7 @@ const (
|
|||||||
TypePushOpacityLen = 1 + 4
|
TypePushOpacityLen = 1 + 4
|
||||||
TypePopOpacityLen = 1
|
TypePopOpacityLen = 1
|
||||||
TypeRedrawLen = 1 + 8
|
TypeRedrawLen = 1 + 8
|
||||||
TypeImageLen = 1
|
TypeImageLen = 1 + 1
|
||||||
TypePaintLen = 1
|
TypePaintLen = 1
|
||||||
TypeColorLen = 1 + 4
|
TypeColorLen = 1 + 4
|
||||||
TypeLinearGradientLen = 1 + 8*2 + 4*2
|
TypeLinearGradientLen = 1 + 8*2 + 4*2
|
||||||
|
|||||||
+2
-2
@@ -8,7 +8,7 @@ object such as a finger.
|
|||||||
The InputOp operation is used to declare a handler ready for pointer
|
The InputOp operation is used to declare a handler ready for pointer
|
||||||
events. Use an event.Queue to receive events.
|
events. Use an event.Queue to receive events.
|
||||||
|
|
||||||
# Types
|
# Kinds
|
||||||
|
|
||||||
Only events that match a specified list of types are delivered to a handler.
|
Only events that match a specified list of types are delivered to a handler.
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ Leave, or Scroll):
|
|||||||
|
|
||||||
pointer.InputOp{
|
pointer.InputOp{
|
||||||
Tag: h,
|
Tag: h,
|
||||||
Types: pointer.Press | pointer.Drag | pointer.Release,
|
Kinds: pointer.Press | pointer.Drag | pointer.Release,
|
||||||
}.Add(ops)
|
}.Add(ops)
|
||||||
|
|
||||||
Cancel events are always delivered.
|
Cancel events are always delivered.
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ type Event struct {
|
|||||||
Time time.Duration
|
Time time.Duration
|
||||||
// Buttons are the set of pressed mouse buttons for this event.
|
// Buttons are the set of pressed mouse buttons for this event.
|
||||||
Buttons Buttons
|
Buttons Buttons
|
||||||
// Position is the position of the event, relative to
|
// Position is the coordinates of the event in the local coordinate
|
||||||
// the current transformation, as set by op.TransformOp.
|
// system of the receiving tag. The transformation from global window
|
||||||
|
// coordinates to local coordinates is performed by the inverse of
|
||||||
|
// the effective transformation of the tag.
|
||||||
Position f32.Point
|
Position f32.Point
|
||||||
// Scroll is the scroll amount, if any.
|
// Scroll is the scroll amount, if any.
|
||||||
Scroll f32.Point
|
Scroll f32.Point
|
||||||
|
|||||||
@@ -103,6 +103,30 @@ func ExampleStack() {
|
|||||||
// Expand: {(50,50) (100,100)}
|
// Expand: {(50,50) (100,100)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleBackground() {
|
||||||
|
gtx := layout.Context{
|
||||||
|
Ops: new(op.Ops),
|
||||||
|
Constraints: layout.Constraints{
|
||||||
|
Max: image.Point{X: 100, Y: 100},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.Background{}.Layout(gtx,
|
||||||
|
// Force widget to the same size as the second.
|
||||||
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
|
fmt.Printf("Expand: %v\n", gtx.Constraints)
|
||||||
|
return layoutWidget(gtx, 10, 10)
|
||||||
|
},
|
||||||
|
// Rigid 50x50 widget.
|
||||||
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layoutWidget(gtx, 50, 50)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Expand: {(50,50) (100,100)}
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleList() {
|
func ExampleList() {
|
||||||
gtx := layout.Context{
|
gtx := layout.Context{
|
||||||
Ops: new(op.Ops),
|
Ops: new(op.Ops),
|
||||||
|
|||||||
@@ -118,3 +118,36 @@ func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions {
|
|||||||
Baseline: baseline,
|
Baseline: baseline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Background lays out single child widget on top of a background,
|
||||||
|
// centering, if necessary.
|
||||||
|
type Background struct{}
|
||||||
|
|
||||||
|
// Layout a widget and then add a background to it.
|
||||||
|
func (Background) Layout(gtx Context, background, widget Widget) Dimensions {
|
||||||
|
macro := op.Record(gtx.Ops)
|
||||||
|
wdims := widget(gtx)
|
||||||
|
baseline := wdims.Baseline
|
||||||
|
call := macro.Stop()
|
||||||
|
|
||||||
|
cgtx := gtx
|
||||||
|
cgtx.Constraints.Min = gtx.Constraints.Constrain(wdims.Size)
|
||||||
|
bdims := background(cgtx)
|
||||||
|
|
||||||
|
if bdims.Size != wdims.Size {
|
||||||
|
p := image.Point{
|
||||||
|
X: (bdims.Size.X - wdims.Size.X) / 2,
|
||||||
|
Y: (bdims.Size.Y - wdims.Size.Y) / 2,
|
||||||
|
}
|
||||||
|
baseline += (bdims.Size.Y - wdims.Size.Y) / 2
|
||||||
|
trans := op.Offset(p).Push(gtx.Ops)
|
||||||
|
defer trans.Pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
call.Add(gtx.Ops)
|
||||||
|
|
||||||
|
return Dimensions{
|
||||||
|
Size: bdims.Size,
|
||||||
|
Baseline: baseline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// SPDX-License-Identifier: Unlicense OR MIT
|
||||||
|
|
||||||
|
package layout
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gioui.org/op"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkStack(b *testing.B) {
|
||||||
|
gtx := Context{
|
||||||
|
Ops: new(op.Ops),
|
||||||
|
Constraints: Constraints{
|
||||||
|
Max: image.Point{X: 100, Y: 100},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
gtx.Ops.Reset()
|
||||||
|
|
||||||
|
Stack{}.Layout(gtx,
|
||||||
|
Expanded(emptyWidget{
|
||||||
|
Size: image.Point{X: 60, Y: 60},
|
||||||
|
}.Layout),
|
||||||
|
Stacked(emptyWidget{
|
||||||
|
Size: image.Point{X: 30, Y: 30},
|
||||||
|
}.Layout),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkBackground(b *testing.B) {
|
||||||
|
gtx := Context{
|
||||||
|
Ops: new(op.Ops),
|
||||||
|
Constraints: Constraints{
|
||||||
|
Max: image.Point{X: 100, Y: 100},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
gtx.Ops.Reset()
|
||||||
|
|
||||||
|
Background{}.Layout(gtx,
|
||||||
|
emptyWidget{
|
||||||
|
Size: image.Point{X: 60, Y: 60},
|
||||||
|
}.Layout,
|
||||||
|
emptyWidget{
|
||||||
|
Size: image.Point{X: 30, Y: 30},
|
||||||
|
}.Layout,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type emptyWidget struct {
|
||||||
|
Size image.Point
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w emptyWidget) Layout(gtx Context) Dimensions {
|
||||||
|
return Dimensions{Size: w.Size}
|
||||||
|
}
|
||||||
@@ -15,8 +15,20 @@ import (
|
|||||||
"gioui.org/op/clip"
|
"gioui.org/op/clip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ImageFilter is the scaling filter for images.
|
||||||
|
type ImageFilter byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
// FilterLinear uses linear interpolation for scaling.
|
||||||
|
FilterLinear ImageFilter = iota
|
||||||
|
// FilterNearest uses nearest neighbor interpolation for scaling.
|
||||||
|
FilterNearest
|
||||||
|
)
|
||||||
|
|
||||||
// ImageOp sets the brush to an image.
|
// ImageOp sets the brush to an image.
|
||||||
type ImageOp struct {
|
type ImageOp struct {
|
||||||
|
Filter ImageFilter
|
||||||
|
|
||||||
uniform bool
|
uniform bool
|
||||||
color color.NRGBA
|
color color.NRGBA
|
||||||
src *image.RGBA
|
src *image.RGBA
|
||||||
@@ -103,6 +115,7 @@ func (i ImageOp) Add(o *op.Ops) {
|
|||||||
}
|
}
|
||||||
data := ops.Write2(&o.Internal, ops.TypeImageLen, i.src, i.handle)
|
data := ops.Write2(&o.Internal, ops.TypeImageLen, i.src, i.handle)
|
||||||
data[0] = byte(ops.TypeImage)
|
data[0] = byte(ops.TypeImage)
|
||||||
|
data[1] = byte(i.Filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ColorOp) Add(o *op.Ops) {
|
func (c ColorOp) Add(o *op.Ops) {
|
||||||
|
|||||||
+2
-2
@@ -53,8 +53,8 @@ func (b *Clickable) Click() {
|
|||||||
b.requestClicks++
|
b.requestClicks++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicked reports whether there are pending clicks as would be
|
// Clicked reports whether there are pending clicks. If so, Clicked
|
||||||
// reported by Clicks. If so, Clicked removes the earliest click.
|
// removes the earliest click.
|
||||||
func (b *Clickable) Clicked(gtx layout.Context) bool {
|
func (b *Clickable) Clicked(gtx layout.Context) bool {
|
||||||
if len(b.clicks) > 0 {
|
if len(b.clicks) > 0 {
|
||||||
b.clicks = b.clicks[1:]
|
b.clicks = b.clicks[1:]
|
||||||
|
|||||||
+14
-18
@@ -93,9 +93,8 @@ func IconButton(th *Theme, button *widget.Clickable, icon *widget.Icon, descript
|
|||||||
func Clickable(gtx layout.Context, button *widget.Clickable, w layout.Widget) layout.Dimensions {
|
func Clickable(gtx layout.Context, button *widget.Clickable, w layout.Widget) layout.Dimensions {
|
||||||
return button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
return button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
semantic.Button.Add(gtx.Ops)
|
semantic.Button.Add(gtx.Ops)
|
||||||
constraints := gtx.Constraints
|
return layout.Background{}.Layout(gtx,
|
||||||
return layout.Stack{}.Layout(gtx,
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
defer clip.Rect{Max: gtx.Constraints.Min}.Push(gtx.Ops).Pop()
|
defer clip.Rect{Max: gtx.Constraints.Min}.Push(gtx.Ops).Pop()
|
||||||
if button.Hovered() || button.Focused() {
|
if button.Hovered() || button.Focused() {
|
||||||
paint.Fill(gtx.Ops, f32color.Hovered(color.NRGBA{}))
|
paint.Fill(gtx.Ops, f32color.Hovered(color.NRGBA{}))
|
||||||
@@ -104,11 +103,8 @@ func Clickable(gtx layout.Context, button *widget.Clickable, w layout.Widget) la
|
|||||||
drawInk(gtx, c)
|
drawInk(gtx, c)
|
||||||
}
|
}
|
||||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||||
}),
|
},
|
||||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
w,
|
||||||
gtx.Constraints = constraints
|
|
||||||
return w(gtx)
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -131,8 +127,8 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Di
|
|||||||
min := gtx.Constraints.Min
|
min := gtx.Constraints.Min
|
||||||
return b.Button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
return b.Button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
semantic.Button.Add(gtx.Ops)
|
semantic.Button.Add(gtx.Ops)
|
||||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
return layout.Background{}.Layout(gtx,
|
||||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
rr := gtx.Dp(b.CornerRadius)
|
rr := gtx.Dp(b.CornerRadius)
|
||||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops).Pop()
|
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops).Pop()
|
||||||
background := b.Background
|
background := b.Background
|
||||||
@@ -147,11 +143,11 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Di
|
|||||||
drawInk(gtx, c)
|
drawInk(gtx, c)
|
||||||
}
|
}
|
||||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||||
}),
|
},
|
||||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
gtx.Constraints.Min = min
|
gtx.Constraints.Min = min
|
||||||
return layout.Center.Layout(gtx, w)
|
return layout.Center.Layout(gtx, w)
|
||||||
}),
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -163,8 +159,8 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
if d := b.Description; d != "" {
|
if d := b.Description; d != "" {
|
||||||
semantic.DescriptionOp(b.Description).Add(gtx.Ops)
|
semantic.DescriptionOp(b.Description).Add(gtx.Ops)
|
||||||
}
|
}
|
||||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
return layout.Background{}.Layout(gtx,
|
||||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
rr := (gtx.Constraints.Min.X + gtx.Constraints.Min.Y) / 4
|
rr := (gtx.Constraints.Min.X + gtx.Constraints.Min.Y) / 4
|
||||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops).Pop()
|
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops).Pop()
|
||||||
background := b.Background
|
background := b.Background
|
||||||
@@ -179,8 +175,8 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
drawInk(gtx, c)
|
drawInk(gtx, c)
|
||||||
}
|
}
|
||||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||||
}),
|
},
|
||||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
size := gtx.Dp(b.Size)
|
size := gtx.Dp(b.Size)
|
||||||
if b.Icon != nil {
|
if b.Icon != nil {
|
||||||
@@ -191,7 +187,7 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
|||||||
Size: image.Point{X: size, Y: size},
|
Size: image.Point{X: size, Y: size},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}),
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
c := m.Stop()
|
c := m.Stop()
|
||||||
|
|||||||
@@ -88,18 +88,18 @@ func (d DecorationsStyle) layoutDecorations(gtx layout.Context) layout.Dimension
|
|||||||
cl := d.Decorations.Clickable(a)
|
cl := d.Decorations.Clickable(a)
|
||||||
dims := cl.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
dims := cl.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
semantic.Button.Add(gtx.Ops)
|
semantic.Button.Add(gtx.Ops)
|
||||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
return layout.Background{}.Layout(gtx,
|
||||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
defer clip.Rect{Max: gtx.Constraints.Min}.Push(gtx.Ops).Pop()
|
defer clip.Rect{Max: gtx.Constraints.Min}.Push(gtx.Ops).Pop()
|
||||||
for _, c := range cl.History() {
|
for _, c := range cl.History() {
|
||||||
drawInk(gtx, c)
|
drawInk(gtx, c)
|
||||||
}
|
}
|
||||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||||
}),
|
},
|
||||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
paint.ColorOp{Color: d.Foreground}.Add(gtx.Ops)
|
paint.ColorOp{Color: d.Foreground}.Add(gtx.Ops)
|
||||||
return inset.Layout(gtx, w)
|
return inset.Layout(gtx, w)
|
||||||
}),
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
size.X += dims.Size.X
|
size.X += dims.Size.X
|
||||||
|
|||||||
+6
-10
@@ -165,12 +165,9 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
|
|||||||
if axis == layout.Horizontal {
|
if axis == layout.Horizontal {
|
||||||
inset.Top, inset.Bottom, inset.Left, inset.Right = inset.Left, inset.Right, inset.Top, inset.Bottom
|
inset.Top, inset.Bottom, inset.Left, inset.Right = inset.Left, inset.Right, inset.Top, inset.Bottom
|
||||||
}
|
}
|
||||||
// Capture the outer constraints because layout.Stack will reset
|
|
||||||
// the minimum to zero.
|
|
||||||
outerConstraints := gtx.Constraints
|
|
||||||
|
|
||||||
return layout.Stack{}.Layout(gtx,
|
return layout.Background{}.Layout(gtx,
|
||||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
// Lay out the draggable track underneath the scroll indicator.
|
// Lay out the draggable track underneath the scroll indicator.
|
||||||
area := image.Rectangle{
|
area := image.Rectangle{
|
||||||
Max: gtx.Constraints.Min,
|
Max: gtx.Constraints.Min,
|
||||||
@@ -186,10 +183,9 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
|
|||||||
s.Scrollbar.AddTrack(gtx.Ops)
|
s.Scrollbar.AddTrack(gtx.Ops)
|
||||||
|
|
||||||
paint.FillShape(gtx.Ops, s.Track.Color, clip.Rect(area).Op())
|
paint.FillShape(gtx.Ops, s.Track.Color, clip.Rect(area).Op())
|
||||||
return layout.Dimensions{}
|
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||||
}),
|
},
|
||||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
func(gtx layout.Context) layout.Dimensions {
|
||||||
gtx.Constraints = outerConstraints
|
|
||||||
return inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
return inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
// Use axis-independent constraints.
|
// Use axis-independent constraints.
|
||||||
gtx.Constraints.Min = axis.Convert(gtx.Constraints.Min)
|
gtx.Constraints.Min = axis.Convert(gtx.Constraints.Min)
|
||||||
@@ -231,7 +227,7 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
|
|||||||
|
|
||||||
return layout.Dimensions{Size: axis.Convert(gtx.Constraints.Min)}
|
return layout.Dimensions{Size: axis.Convert(gtx.Constraints.Min)}
|
||||||
})
|
})
|
||||||
}),
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ func RadioButton(th *Theme, group *widget.Enum, key, label string) RadioButtonSt
|
|||||||
|
|
||||||
// Layout updates enum and displays the radio button.
|
// Layout updates enum and displays the radio button.
|
||||||
func (r RadioButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
func (r RadioButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||||
|
r.Group.Update(gtx)
|
||||||
hovered, hovering := r.Group.Hovered()
|
hovered, hovering := r.Group.Hovered()
|
||||||
focus, focused := r.Group.Focused()
|
focus, focused := r.Group.Focused()
|
||||||
return r.Group.Layout(gtx, r.Key, func(gtx layout.Context) layout.Dimensions {
|
return r.Group.Layout(gtx, r.Key, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ func Switch(th *Theme, swtch *widget.Bool, description string) SwitchStyle {
|
|||||||
|
|
||||||
// Layout updates the switch and displays it.
|
// Layout updates the switch and displays it.
|
||||||
func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
|
func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||||
|
s.Switch.Update(gtx)
|
||||||
trackWidth := gtx.Dp(36)
|
trackWidth := gtx.Dp(36)
|
||||||
trackHeight := gtx.Dp(16)
|
trackHeight := gtx.Dp(16)
|
||||||
thumbSize := gtx.Dp(20)
|
thumbSize := gtx.Dp(20)
|
||||||
|
|||||||
Reference in New Issue
Block a user