mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d96c954769 | |||
| f39245df99 | |||
| 8097df9930 | |||
| fc6e51deba | |||
| 5fa94ff67b | |||
| 23b6f06e3e |
+16
-6
@@ -8,16 +8,21 @@ packages:
|
||||
- libxml2-dev
|
||||
- libssl-dev
|
||||
- libz-dev
|
||||
- llvm-dev # for cctools
|
||||
- uuid-dev ## for cctools
|
||||
- llvm-dev # cctools
|
||||
- uuid-dev # cctools
|
||||
- ninja-build # cctools
|
||||
- systemtap-sdt-dev # cctools
|
||||
- libbsd-dev # cctools
|
||||
- linux-libc-dev # cctools
|
||||
- libplist-utils # for gogio
|
||||
sources:
|
||||
- https://git.sr.ht/~eliasnaur/applesdks
|
||||
- https://git.sr.ht/~eliasnaur/gio
|
||||
- https://git.sr.ht/~eliasnaur/giouiorg
|
||||
- https://github.com/tpoechtrager/cctools-port.git
|
||||
- https://github.com/tpoechtrager/apple-libtapi.git
|
||||
- https://github.com/mackyle/xar.git
|
||||
- https://github.com/tpoechtrager/cctools-port
|
||||
- https://github.com/tpoechtrager/apple-libtapi
|
||||
- https://github.com/tpoechtrager/apple-libdispatch
|
||||
- https://github.com/mackyle/xar
|
||||
environment:
|
||||
APPLE_TOOLCHAIN_ROOT: /home/build/appletools
|
||||
PATH: /home/build/sdk/go/bin:/home/build/go/bin:/usr/bin
|
||||
@@ -42,6 +47,11 @@ tasks:
|
||||
- install_appletoolchain: |
|
||||
cd giouiorg
|
||||
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: |
|
||||
cd xar/xar
|
||||
ac_cv_lib_crypto_OpenSSL_add_all_ciphers=yes CC=clang ./autogen.sh --prefix=/usr
|
||||
@@ -53,7 +63,7 @@ tasks:
|
||||
./install.sh
|
||||
- build_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
|
||||
- test_macos: |
|
||||
cd gio
|
||||
|
||||
@@ -192,6 +192,10 @@ static CFTypeRef windowForView(CFTypeRef viewRef) {
|
||||
}
|
||||
|
||||
static void raiseWindow(CFTypeRef windowRef) {
|
||||
NSRunningApplication *currentApp = [NSRunningApplication currentApplication];
|
||||
if (![currentApp isActive]) {
|
||||
[currentApp activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
|
||||
}
|
||||
NSWindow* window = (__bridge NSWindow *)windowRef;
|
||||
[window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
+32
-3
@@ -186,10 +186,16 @@ type material struct {
|
||||
uvTrans f32.Affine2D
|
||||
}
|
||||
|
||||
const (
|
||||
filterLinear = 0
|
||||
filterNearest = 1
|
||||
)
|
||||
|
||||
// imageOpData is the shadow of paint.ImageOp.
|
||||
type imageOpData struct {
|
||||
src *image.RGBA
|
||||
handle interface{}
|
||||
filter byte
|
||||
}
|
||||
|
||||
type linearGradientOpData struct {
|
||||
@@ -207,6 +213,7 @@ func decodeImageOp(data []byte, refs []interface{}) imageOpData {
|
||||
return imageOpData{
|
||||
src: refs[0].(*image.RGBA),
|
||||
handle: handle,
|
||||
filter: data[1],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,19 +461,41 @@ func (g *gpu) Profile() string {
|
||||
}
|
||||
|
||||
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
|
||||
t, exists := cache.get(data.handle)
|
||||
t, exists := cache.get(key)
|
||||
if !exists {
|
||||
t = &texture{
|
||||
src: data.src,
|
||||
}
|
||||
cache.put(data.handle, t)
|
||||
cache.put(key, t)
|
||||
}
|
||||
tex = t.(*texture)
|
||||
if tex.tex != nil {
|
||||
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 {
|
||||
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) {
|
||||
ops := new(op.Ops)
|
||||
var p clip.Path
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ const (
|
||||
TypePushOpacityLen = 1 + 4
|
||||
TypePopOpacityLen = 1
|
||||
TypeRedrawLen = 1 + 8
|
||||
TypeImageLen = 1
|
||||
TypeImageLen = 1 + 1
|
||||
TypePaintLen = 1
|
||||
TypeColorLen = 1 + 4
|
||||
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
|
||||
events. Use an event.Queue to receive events.
|
||||
|
||||
# Types
|
||||
# Kinds
|
||||
|
||||
Only events that match a specified list of types are delivered to a handler.
|
||||
|
||||
@@ -20,7 +20,7 @@ Leave, or Scroll):
|
||||
|
||||
pointer.InputOp{
|
||||
Tag: h,
|
||||
Types: pointer.Press | pointer.Drag | pointer.Release,
|
||||
Kinds: pointer.Press | pointer.Drag | pointer.Release,
|
||||
}.Add(ops)
|
||||
|
||||
Cancel events are always delivered.
|
||||
|
||||
@@ -32,8 +32,10 @@ type Event struct {
|
||||
Time time.Duration
|
||||
// Buttons are the set of pressed mouse buttons for this event.
|
||||
Buttons Buttons
|
||||
// Position is the position of the event, relative to
|
||||
// the current transformation, as set by op.TransformOp.
|
||||
// Position is the coordinates of the event in the local coordinate
|
||||
// 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
|
||||
// Scroll is the scroll amount, if any.
|
||||
Scroll f32.Point
|
||||
|
||||
@@ -103,6 +103,30 @@ func ExampleStack() {
|
||||
// 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() {
|
||||
gtx := layout.Context{
|
||||
Ops: new(op.Ops),
|
||||
|
||||
@@ -118,3 +118,36 @@ func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions {
|
||||
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"
|
||||
)
|
||||
|
||||
// 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.
|
||||
type ImageOp struct {
|
||||
Filter ImageFilter
|
||||
|
||||
uniform bool
|
||||
color color.NRGBA
|
||||
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[0] = byte(ops.TypeImage)
|
||||
data[1] = byte(i.Filter)
|
||||
}
|
||||
|
||||
func (c ColorOp) Add(o *op.Ops) {
|
||||
|
||||
+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 {
|
||||
return button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
semantic.Button.Add(gtx.Ops)
|
||||
constraints := gtx.Constraints
|
||||
return layout.Stack{}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx layout.Context) layout.Dimensions {
|
||||
defer clip.Rect{Max: gtx.Constraints.Min}.Push(gtx.Ops).Pop()
|
||||
if button.Hovered() || button.Focused() {
|
||||
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)
|
||||
}
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
}),
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
gtx.Constraints = constraints
|
||||
return w(gtx)
|
||||
}),
|
||||
},
|
||||
w,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -131,8 +127,8 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Di
|
||||
min := gtx.Constraints.Min
|
||||
return b.Button.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
semantic.Button.Add(gtx.Ops)
|
||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx layout.Context) layout.Dimensions {
|
||||
rr := gtx.Dp(b.CornerRadius)
|
||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops).Pop()
|
||||
background := b.Background
|
||||
@@ -147,11 +143,11 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Di
|
||||
drawInk(gtx, c)
|
||||
}
|
||||
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
|
||||
return layout.Center.Layout(gtx, w)
|
||||
}),
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -163,8 +159,8 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||
if d := b.Description; d != "" {
|
||||
semantic.DescriptionOp(b.Description).Add(gtx.Ops)
|
||||
}
|
||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx layout.Context) layout.Dimensions {
|
||||
rr := (gtx.Constraints.Min.X + gtx.Constraints.Min.Y) / 4
|
||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops).Pop()
|
||||
background := b.Background
|
||||
@@ -179,8 +175,8 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||
drawInk(gtx, c)
|
||||
}
|
||||
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 {
|
||||
size := gtx.Dp(b.Size)
|
||||
if b.Icon != nil {
|
||||
@@ -191,7 +187,7 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||
Size: image.Point{X: size, Y: size},
|
||||
}
|
||||
})
|
||||
}),
|
||||
},
|
||||
)
|
||||
})
|
||||
c := m.Stop()
|
||||
|
||||
@@ -88,18 +88,18 @@ func (d DecorationsStyle) layoutDecorations(gtx layout.Context) layout.Dimension
|
||||
cl := d.Decorations.Clickable(a)
|
||||
dims := cl.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
semantic.Button.Add(gtx.Ops)
|
||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx layout.Context) layout.Dimensions {
|
||||
defer clip.Rect{Max: gtx.Constraints.Min}.Push(gtx.Ops).Pop()
|
||||
for _, c := range cl.History() {
|
||||
drawInk(gtx, c)
|
||||
}
|
||||
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)
|
||||
return inset.Layout(gtx, w)
|
||||
}),
|
||||
},
|
||||
)
|
||||
})
|
||||
size.X += dims.Size.X
|
||||
|
||||
@@ -169,8 +169,8 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
|
||||
// the minimum to zero.
|
||||
outerConstraints := gtx.Constraints
|
||||
|
||||
return layout.Stack{}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx layout.Context) layout.Dimensions {
|
||||
// Lay out the draggable track underneath the scroll indicator.
|
||||
area := image.Rectangle{
|
||||
Max: gtx.Constraints.Min,
|
||||
@@ -187,8 +187,8 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
|
||||
|
||||
paint.FillShape(gtx.Ops, s.Track.Color, clip.Rect(area).Op())
|
||||
return layout.Dimensions{}
|
||||
}),
|
||||
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 {
|
||||
// Use axis-independent constraints.
|
||||
@@ -231,7 +231,7 @@ func (s ScrollbarStyle) layout(gtx layout.Context, axis layout.Axis, viewportSta
|
||||
|
||||
return layout.Dimensions{Size: axis.Convert(gtx.Constraints.Min)}
|
||||
})
|
||||
}),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user