This commit is contained in:
zervo 2025-01-31 23:20:05 +01:00
parent 867a3d0fcd
commit 99cf3b3843
7 changed files with 119 additions and 29 deletions

View file

@ -8,6 +8,7 @@ require (
)
require (
gio.tools/icons v0.0.0-20240708021058-44790e75e701 // indirect
gioui.org/shader v1.0.8 // indirect
github.com/go-text/typesetting v0.2.1 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect

View file

@ -1,5 +1,7 @@
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY=
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA=
gio.tools/icons v0.0.0-20240708021058-44790e75e701 h1:uLF9lM2XdkhjH2bhWdTEONz9y4nuweF377ice94rNVQ=
gio.tools/icons v0.0.0-20240708021058-44790e75e701/go.mod h1:yHac4ydqWEu6ZgRJ2c2izqy285pdJRHZczqlbhDZIi0=
gioui.org v0.8.0 h1:QV5p5JvsmSmGiIXVYOKn6d9YDliTfjtLlVf5J+BZ9Pg=
gioui.org v0.8.0/go.mod h1:vEMmpxMOd/iwJhXvGVIzWEbxMWhnMQ9aByOGQdlQ8rc=
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=

View file

@ -1,20 +1,19 @@
package ui
import (
"icdb/internal/ui/styling"
"icdb/pkg/layouts"
t_ui "icdb/pkg/types/ui"
"gioui.org/app"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/unit"
"gioui.org/widget/material"
)
var currentView t_ui.UIView = t_ui.UIViewMain
// run takes a window as parameter and runs the UI on it.
func run(window *app.Window) error {
theme := material.NewTheme()
theme := styling.GlobalTheme()
var ops op.Ops
for {
switch e := window.Event().(type) {
@ -23,21 +22,10 @@ func run(window *app.Window) error {
case app.FrameEvent:
gtx := app.NewContext(&ops, e)
margins := layout.Inset{
Top: unit.Dp(10),
Bottom: unit.Dp(10),
Left: unit.Dp(10),
Right: unit.Dp(10),
}
margins.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Flex{
Axis: layout.Horizontal,
}.Layout(gtx,
layout.Rigid(renderSidebar(theme)),
layout.Flexed(1, renderView(theme)),
)
})
layouts.SplitRatio{Ratio: -0.8}.Layout(gtx,
renderSidebar(theme),
renderView(theme),
)
e.Frame(gtx.Ops)
}

View file

@ -2,9 +2,13 @@ package ui
import (
t_ui "icdb/pkg/types/ui"
"image"
"image/color"
"gio.tools/icons"
"gioui.org/layout"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
@ -17,27 +21,63 @@ var (
)
var sidebarWidth = unit.Dp(200)
var sidebarBackground = color.NRGBA{R: 240, G: 240, B: 240, A: 255}
var sidebarBackground = color.NRGBA{R: 225, G: 225, B: 225, A: 255}
// renderSidebar creates the sidebar UI.
// It renders a colored background and then adds the navigation buttons.
func renderSidebar(th *material.Theme) layout.Widget {
return func(gtx layout.Context) layout.Dimensions {
return layout.Flex{
Axis: layout.Vertical,
}.Layout(gtx,
layout.Rigid(renderNavButton(gtx, th, "Main", &mainButton, t_ui.UIViewMain)),
layout.Rigid(renderNavButton(gtx, th, "Parts", &partsButton, t_ui.UIViewParts)),
layout.Rigid(renderNavButton(gtx, th, "Settings", &settingsButton, t_ui.UIViewSettings)),
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
// Expanded: Draw the background to fill the entire left pane.
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
// Use a rectangle that covers the full widget area.
rect := clip.Rect{
Min: image.Pt(0, 0),
Max: gtx.Constraints.Max,
}
paint.FillShape(gtx.Ops, sidebarBackground, rect.Op())
return layout.Dimensions{Size: gtx.Constraints.Max}
}),
// Stacked: Lay out the navigation buttons.
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
// Internal padding for the sidebar.
in := layout.Inset{
Top: unit.Dp(5),
Left: unit.Dp(5),
Right: unit.Dp(5),
Bottom: unit.Dp(5),
}
return in.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Flex{
Axis: layout.Vertical,
Alignment: layout.Start,
}.Layout(gtx,
layout.Rigid(renderNavButton(th, icons.ActionHome, "Main", &mainButton, t_ui.UIViewMain)),
layout.Rigid(renderNavButton(th, icons.ActionBuild, "Parts", &partsButton, t_ui.UIViewParts)),
layout.Rigid(renderNavButton(th, icons.ActionSettings, "Settings", &settingsButton, t_ui.UIViewSettings)),
)
})
}),
)
}
}
// renderNavButton creates a navigation button
func renderNavButton(gtx layout.Context, th *material.Theme, label string, btn *widget.Clickable, target t_ui.UIView) layout.Widget {
// renderNavButton creates a navigation icon button.
func renderNavButton(th *material.Theme, icon *widget.Icon, label string, btn *widget.Clickable, target t_ui.UIView) layout.Widget {
return func(gtx layout.Context) layout.Dimensions {
if btn.Clicked(gtx) {
currentView = target
}
return material.Button(th, btn, label).Layout(gtx)
// Padding for each button, to add spacing between them.
in := layout.Inset{
Bottom: unit.Dp(8),
Left: unit.Dp(4),
Right: unit.Dp(4),
}
return in.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return material.IconButton(th, btn, icon, label).Layout(gtx)
})
}
}

View file

@ -0,0 +1,17 @@
package styling
import (
"image/color"
"gioui.org/widget/material"
"golang.org/x/image/colornames"
)
// GlobalTheme returns an instance of the global application theme.
func GlobalTheme() *material.Theme {
theme := material.NewTheme()
theme.Palette.Bg = color.NRGBA(colornames.White)
theme.Palette.Fg = color.NRGBA(colornames.Black)
theme.ContrastBg = color.NRGBA(colornames.Orange)
return theme
}

View file

@ -4,6 +4,7 @@ import (
"os"
"gioui.org/app"
"gioui.org/unit"
"github.com/rs/zerolog/log"
)
@ -11,6 +12,9 @@ import (
func Init() {
go func() {
window := new(app.Window)
window.Option(app.Title("ICDB"))
window.Option(app.MinSize(unit.Dp(700), unit.Dp(400)))
window.Option(app.Size(unit.Dp(800), unit.Dp(600)))
err := run(window)
if err != nil {
log.Fatal().Err(err).Msg("UI loop exited with error")

38
src/pkg/layouts/split.go Normal file
View file

@ -0,0 +1,38 @@
package layouts
import (
"image"
"gioui.org/layout"
"gioui.org/op"
)
type SplitRatio struct {
// Ratio keeps the current layout.
// 0 is center, -1 completely to the left, 1 completely to the right.
Ratio float32
}
func (s SplitRatio) Layout(gtx layout.Context, left, right layout.Widget) layout.Dimensions {
proportion := (s.Ratio + 1) / 2
leftsize := int(proportion * float32(gtx.Constraints.Max.X))
rightoffset := leftsize
rightsize := gtx.Constraints.Max.X - rightoffset
{
gtx := gtx
gtx.Constraints = layout.Exact(image.Pt(leftsize, gtx.Constraints.Max.Y))
left(gtx)
}
{
trans := op.Offset(image.Pt(rightoffset, 0)).Push(gtx.Ops)
gtx := gtx
gtx.Constraints = layout.Exact(image.Pt(rightsize, gtx.Constraints.Max.Y))
right(gtx)
trans.Pop()
}
return layout.Dimensions{Size: gtx.Constraints.Max}
}