mirror of
https://github.com/vsariola/sointu.git
synced 2025-05-25 18:00:37 -04:00
feat(tracker/gioui): rewrite the numeric updown, with new appearance
This commit is contained in:
parent
bdf9e2ba0c
commit
d0413e0a13
@ -87,6 +87,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
([#156][i156])
|
||||
|
||||
### Changed
|
||||
- The numeric updown widget has a new appearance.
|
||||
- The draggable UI splitters snap more controllably to the window edges.
|
||||
- New & better presets, organized by their type to subfolders (thanks Reaby!)
|
||||
([#136][i136])
|
||||
|
@ -1,14 +1,15 @@
|
||||
package gioui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"strconv"
|
||||
|
||||
"github.com/vsariola/sointu/tracker"
|
||||
"golang.org/x/exp/shiny/materialdesign/icons"
|
||||
|
||||
"gioui.org/font"
|
||||
"gioui.org/op"
|
||||
"gioui.org/op/clip"
|
||||
"gioui.org/op/paint"
|
||||
"gioui.org/widget"
|
||||
@ -18,7 +19,6 @@ import (
|
||||
"gioui.org/io/event"
|
||||
"gioui.org/io/pointer"
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
"gioui.org/text"
|
||||
"gioui.org/unit"
|
||||
"gioui.org/widget/material"
|
||||
@ -56,16 +56,11 @@ func NewNumberInput(v tracker.Int) *NumberInput {
|
||||
}
|
||||
|
||||
func NumericUpDown(th *material.Theme, number *NumberInput, tooltip string) NumericUpDownStyle {
|
||||
bgColor := th.Palette.Fg
|
||||
bgColor.R /= 4
|
||||
bgColor.G /= 4
|
||||
bgColor.B /= 4
|
||||
return NumericUpDownStyle{
|
||||
NumberInput: number,
|
||||
Color: white,
|
||||
BorderColor: th.Palette.Fg,
|
||||
IconColor: th.Palette.ContrastFg,
|
||||
BackgroundColor: bgColor,
|
||||
IconColor: th.Palette.Fg,
|
||||
BackgroundColor: numberInputBgColor,
|
||||
CornerRadius: unit.Dp(4),
|
||||
ButtonWidth: unit.Dp(16),
|
||||
Border: unit.Dp(1),
|
||||
@ -78,6 +73,43 @@ func NumericUpDown(th *material.Theme, number *NumberInput, tooltip string) Nume
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NumericUpDownStyle) Update(gtx layout.Context) {
|
||||
// handle dragging
|
||||
pxPerStep := float32(gtx.Dp(s.UnitsPerStep))
|
||||
for {
|
||||
ev, ok := gtx.Event(pointer.Filter{
|
||||
Target: s.NumberInput,
|
||||
Kinds: pointer.Press | pointer.Drag | pointer.Release,
|
||||
})
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
if e, ok := ev.(pointer.Event); ok {
|
||||
switch e.Kind {
|
||||
case pointer.Press:
|
||||
s.NumberInput.dragStartValue = s.NumberInput.Int.Value()
|
||||
s.NumberInput.dragStartXY = e.Position.X - e.Position.Y
|
||||
case pointer.Drag:
|
||||
var deltaCoord float32
|
||||
deltaCoord = e.Position.X - e.Position.Y - s.NumberInput.dragStartXY
|
||||
s.NumberInput.Int.Set(s.NumberInput.dragStartValue + int(deltaCoord/pxPerStep+0.5))
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle decrease clicks
|
||||
for ev, ok := s.NumberInput.clickDecrease.Update(gtx.Source); ok; ev, ok = s.NumberInput.clickDecrease.Update(gtx.Source) {
|
||||
if ev.Kind == gesture.KindClick {
|
||||
s.NumberInput.Int.Add(-1)
|
||||
}
|
||||
}
|
||||
// handle increase clicks
|
||||
for ev, ok := s.NumberInput.clickIncrease.Update(gtx.Source); ok; ev, ok = s.NumberInput.clickIncrease.Update(gtx.Source) {
|
||||
if ev.Kind == gesture.KindClick {
|
||||
s.NumberInput.Int.Add(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NumericUpDownStyle) Layout(gtx C) D {
|
||||
if s.Tooltip.Text.Text != "" {
|
||||
return s.NumberInput.tipArea.Layout(gtx, s.Tooltip, s.actualLayout)
|
||||
@ -85,119 +117,47 @@ func (s *NumericUpDownStyle) Layout(gtx C) D {
|
||||
return s.actualLayout(gtx)
|
||||
}
|
||||
|
||||
func (s *NumericUpDownStyle) actualLayout(gtx C) D {
|
||||
size := image.Pt(gtx.Dp(s.Width), gtx.Dp(s.Height))
|
||||
gtx.Constraints.Min = size
|
||||
rr := gtx.Dp(s.CornerRadius)
|
||||
border := gtx.Dp(s.Border)
|
||||
c := clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, rr).Push(gtx.Ops)
|
||||
paint.Fill(gtx.Ops, s.BorderColor)
|
||||
c.Pop()
|
||||
off := op.Offset(image.Pt(border, border)).Push(gtx.Ops)
|
||||
c2 := clip.UniformRRect(image.Rectangle{Max: image.Pt(
|
||||
gtx.Constraints.Min.X-border*2,
|
||||
gtx.Constraints.Min.Y-border*2,
|
||||
)}, rr-border).Push(gtx.Ops)
|
||||
gtx.Constraints.Min.X -= int(border * 2)
|
||||
gtx.Constraints.Min.Y -= int(border * 2)
|
||||
gtx.Constraints.Max = gtx.Constraints.Min
|
||||
layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(s.button(gtx.Constraints.Max.Y, widgetForIcon(icons.NavigationArrowBack), -1, &s.NumberInput.clickDecrease)),
|
||||
layout.Flexed(1, s.layoutText),
|
||||
layout.Rigid(s.button(gtx.Constraints.Max.Y, widgetForIcon(icons.NavigationArrowForward), 1, &s.NumberInput.clickIncrease)),
|
||||
)
|
||||
off.Pop()
|
||||
c2.Pop()
|
||||
return layout.Dimensions{Size: size}
|
||||
}
|
||||
|
||||
func (s *NumericUpDownStyle) button(height int, icon *widget.Icon, delta int, click *gesture.Click) layout.Widget {
|
||||
return func(gtx C) D {
|
||||
width := gtx.Dp(s.ButtonWidth)
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx C) D {
|
||||
if icon != nil {
|
||||
return icon.Layout(gtx, s.IconColor)
|
||||
}
|
||||
return layout.Dimensions{Size: image.Point{X: width, Y: height}}
|
||||
},
|
||||
func(gtx C) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(width, height))
|
||||
return s.layoutClick(gtx, delta, click)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NumericUpDownStyle) layoutText(gtx C) D {
|
||||
func (s NumericUpDownStyle) actualLayout(gtx C) D {
|
||||
s.Update(gtx)
|
||||
gtx.Constraints = layout.Exact(image.Pt(gtx.Dp(s.Width), gtx.Dp(s.Height)))
|
||||
width := gtx.Dp(s.ButtonWidth)
|
||||
height := gtx.Dp(s.Height)
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx C) D {
|
||||
paint.FillShape(gtx.Ops, s.BackgroundColor, clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Op())
|
||||
paint.ColorOp{Color: s.Color}.Add(gtx.Ops)
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, &s.shaper, s.Font, s.TextSize, fmt.Sprintf("%v", s.NumberInput.Int.Value()), op.CallOp{})
|
||||
defer clip.UniformRRect(image.Rectangle{Max: gtx.Constraints.Min}, gtx.Dp(s.CornerRadius)).Push(gtx.Ops).Pop()
|
||||
paint.Fill(gtx.Ops, s.BackgroundColor)
|
||||
event.Op(gtx.Ops, s.NumberInput) // register drag inputs, if not hitting the clicks
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
},
|
||||
func(gtx C) D {
|
||||
gtx.Constraints.Min = gtx.Constraints.Max
|
||||
return s.layoutDrag(gtx)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *NumericUpDownStyle) layoutDrag(gtx layout.Context) layout.Dimensions {
|
||||
{ // handle dragging
|
||||
pxPerStep := float32(gtx.Dp(s.UnitsPerStep))
|
||||
for {
|
||||
ev, ok := gtx.Event(pointer.Filter{
|
||||
Target: s.NumberInput,
|
||||
Kinds: pointer.Press | pointer.Drag | pointer.Release,
|
||||
})
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
if e, ok := ev.(pointer.Event); ok {
|
||||
switch e.Kind {
|
||||
case pointer.Press:
|
||||
s.NumberInput.dragStartValue = s.NumberInput.Int.Value()
|
||||
s.NumberInput.dragStartXY = e.Position.X - e.Position.Y
|
||||
|
||||
case pointer.Drag:
|
||||
var deltaCoord float32
|
||||
deltaCoord = e.Position.X - e.Position.Y - s.NumberInput.dragStartXY
|
||||
s.NumberInput.Int.Set(s.NumberInput.dragStartValue + int(deltaCoord/pxPerStep+0.5))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid affecting the input tree with pointer events.
|
||||
stack := op.Offset(image.Point{}).Push(gtx.Ops)
|
||||
// register for input
|
||||
dragRect := image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||
area := clip.Rect(dragRect).Push(gtx.Ops)
|
||||
event.Op(gtx.Ops, s.NumberInput)
|
||||
area.Pop()
|
||||
stack.Pop()
|
||||
}
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
}
|
||||
|
||||
func (s *NumericUpDownStyle) layoutClick(gtx layout.Context, delta int, click *gesture.Click) layout.Dimensions {
|
||||
// handle clicking
|
||||
for {
|
||||
ev, ok := click.Update(gtx.Source)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
switch ev.Kind {
|
||||
case gesture.KindClick:
|
||||
s.NumberInput.Int.Add(delta)
|
||||
}
|
||||
}
|
||||
// Avoid affecting the input tree with pointer events.
|
||||
stack := op.Offset(image.Point{}).Push(gtx.Ops)
|
||||
|
||||
// register for input
|
||||
clickRect := image.Rect(0, 0, gtx.Constraints.Min.X, gtx.Constraints.Min.Y)
|
||||
area := clip.Rect(clickRect).Push(gtx.Ops)
|
||||
click.Add(gtx.Ops)
|
||||
area.Pop()
|
||||
stack.Pop()
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
return layout.Flex{Axis: layout.Horizontal, Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(width, height))
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx C) D {
|
||||
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Min}).Push(gtx.Ops).Pop()
|
||||
s.NumberInput.clickDecrease.Add(gtx.Ops)
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
},
|
||||
func(gtx C) D { return widgetForIcon(icons.ContentRemove).Layout(gtx, s.IconColor) },
|
||||
)
|
||||
}),
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
paint.ColorOp{Color: s.Color}.Add(gtx.Ops)
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, &s.shaper, s.Font, s.TextSize, strconv.Itoa(s.NumberInput.Int.Value()), op.CallOp{})
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
gtx.Constraints = layout.Exact(image.Pt(width, height))
|
||||
return layout.Background{}.Layout(gtx,
|
||||
func(gtx C) D {
|
||||
defer clip.Rect(image.Rectangle{Max: gtx.Constraints.Min}).Push(gtx.Ops).Pop()
|
||||
s.NumberInput.clickIncrease.Add(gtx.Ops)
|
||||
return D{Size: gtx.Constraints.Min}
|
||||
},
|
||||
func(gtx C) D { return widgetForIcon(icons.ContentAdd).Layout(gtx, s.IconColor) },
|
||||
)
|
||||
}),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -57,6 +57,8 @@ var dragListHoverColor = color.NRGBA{R: 42, G: 45, B: 61, A: 255}
|
||||
var inactiveLightSurfaceColor = color.NRGBA{R: 37, G: 37, B: 38, A: 255}
|
||||
var activeLightSurfaceColor = color.NRGBA{R: 45, G: 45, B: 45, A: 255}
|
||||
|
||||
var numberInputBgColor = color.NRGBA{R: 255, G: 255, B: 255, A: 3}
|
||||
|
||||
var cursorColor = color.NRGBA{R: 100, G: 140, B: 255, A: 48}
|
||||
var selectionColor = color.NRGBA{R: 100, G: 140, B: 255, A: 12}
|
||||
var inactiveSelectionColor = color.NRGBA{R: 140, G: 140, B: 140, A: 16}
|
||||
|
Loading…
Reference in New Issue
Block a user