From 185c84742a4bd0201483aa89c1a4aef540c3c298 Mon Sep 17 00:00:00 2001 From: mStar Date: Mon, 3 Feb 2025 08:22:01 +0100 Subject: [PATCH] batman --- constants.go | 7 ++++ go.mod | 18 +++++++++++ go.sum | 33 +++++++++++++++++++ main.go | 33 +++++++++++++++++++ window.go | 62 +++++++++++++++++++++++++++++++++++ windowEnterTime.go | 81 ++++++++++++++++++++++++++++++++++++++++++++++ windowState.go | 20 ++++++++++++ 7 files changed, 254 insertions(+) create mode 100644 constants.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 window.go create mode 100644 windowEnterTime.go create mode 100644 windowState.go diff --git a/constants.go b/constants.go new file mode 100644 index 0000000..9fd6db3 --- /dev/null +++ b/constants.go @@ -0,0 +1,7 @@ +package main + +import "image/color" + +var ( + ColorRed = color.NRGBA{R: 0xff, G: 0x0, B: 0x0, A: 255} +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2c288ff --- /dev/null +++ b/go.mod @@ -0,0 +1,18 @@ +module git.mstar.dev/mstar/timer + +go 1.23.5 + +require ( + gioui.org v0.8.0 // indirect + gioui.org/shader v1.0.8 // indirect + git.mstar.dev/mstar/goutils v1.6.1 // indirect + github.com/go-text/typesetting v0.2.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/rs/zerolog v1.33.0 // indirect + golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect + golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 // indirect + golang.org/x/image v0.18.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e8a7bac --- /dev/null +++ b/go.sum @@ -0,0 +1,33 @@ +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= +gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA= +gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= +git.mstar.dev/mstar/goutils v1.6.1 h1:2yr9GYN8CJByZsJRu1pZ6WBp51Nn+3zJq49ky54xYDk= +git.mstar.dev/mstar/goutils v1.6.1/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8= +github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 h1:SOSg7+sueresE4IbmmGM60GmlIys+zNX63d6/J4CMtU= +golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o= +golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..116d0ae --- /dev/null +++ b/main.go @@ -0,0 +1,33 @@ +package main + +import ( + "os" + "time" + + "gioui.org/app" + "github.com/rs/zerolog/log" +) + +var t time.Time + +func main() { + window := new(app.Window) + var err error + t, err = time.Parse(time.RFC3339, "2025-01-31T22:50:00Z") + if err != nil { + log.Fatal().Err(err).Send() + } + go func() { + // window.Option(func(m unit.Metric, c *app.Config) { + // c.Size = image.Pt(500, 150) + // c.MaxSize = image.Pt(500, 150) + // c.MinSize = image.Pt(500, 150) + // }) + err := run(window, &StateEnterTime{}) + if err != nil { + log.Fatal().Err(err).Msg("Failed to run main window") + } + os.Exit(0) + }() + app.Main() +} diff --git a/window.go b/window.go new file mode 100644 index 0000000..3ba33b7 --- /dev/null +++ b/window.go @@ -0,0 +1,62 @@ +package main + +import ( + "image/color" + "os" + "time" + + "gioui.org/app" + "gioui.org/widget/material" +) + +type GlobalState struct { + Window *app.Window + Theme *material.Theme + state WindowState +} + +func ticker(window *app.Window) { + t := time.NewTicker(time.Second) + for range t.C { + window.Invalidate() + } +} + +func run(window *app.Window, initialState WindowState) error { + state := GlobalState{} + theme := material.NewTheme() + theme.Bg = color.NRGBA{A: 0xff} + state.Theme = theme + state.Window = window + state.state = initialState + for { + e := window.Event() + newState := state.state.Run(&state, e) + if newState.NextState != nil { + state.state = newState.NextState + } + if newState.ExitCode != nil { + os.Exit(*newState.ExitCode) + } + // log.Debug().Any("size", e.Size).Msg("Redrawing") + // // This graphics context is used for managing the rendering state. + // gtx := app.NewContext(&ops, e) + // paint.FillShape(gtx.Ops, theme.Bg, clip.Rect(image.Rect(0, 0, gtx.Constraints.Max.X, gtx.Constraints.Max.Y)).Op()) + // // + // // // Define an large label with an appropriate text: + // log.Debug().Dur("d", t.Sub(e.Now)).Time("t", t).Send() + // title := material.H1(theme, e.Now.Sub(t).Round(time.Second).String()) + // // + // // // Change the color of the label. + // maroon := color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 255} + // title.Color = maroon + // // + // // // Change the position of the label. + // title.Alignment = text.Middle + // + // // Draw the label to the graphics context. + // title.Layout(gtx) + // // Pass the drawing operations to the GPU. + // e.Frame(&ops) + } +} diff --git a/windowEnterTime.go b/windowEnterTime.go new file mode 100644 index 0000000..7cfb57a --- /dev/null +++ b/windowEnterTime.go @@ -0,0 +1,81 @@ +package main + +import ( + "gioui.org/app" + "gioui.org/io/event" + "gioui.org/layout" + "gioui.org/op" + "gioui.org/widget" + "gioui.org/widget/material" + "git.mstar.dev/mstar/goutils/other" + "github.com/rs/zerolog/log" +) + +type StateEnterTime struct { + initialSetupDone bool + editor *widget.Editor + inputField *material.EditorStyle + ops op.Ops +} + +func (s *StateEnterTime) initialSetup(globalState *GlobalState) { + s.editor = &widget.Editor{ + SingleLine: true, + Submit: true, + Filter: "01234567890TZ+-:", + } + field := material.Editor(globalState.Theme, s.editor, "timestamp") + s.inputField = &field + s.initialSetupDone = true +} + +func (s *StateEnterTime) Run(globalState *GlobalState, event event.Event) NewState { + if !s.initialSetupDone { + s.initialSetup(globalState) + } + switch event := event.(type) { + case app.FrameEvent: + return s.handleFrameEvent(globalState, &event) + case app.DestroyEvent: + return s.handleQuitEvent() + case app.WaylandViewEvent, app.X11ViewEvent: + return EmptyEvent() + default: + log.Debug().Any("event", event).Type("type", event).Msg("Unknown event") + return NewState{} + } +} + +func (s *StateEnterTime) handleFrameEvent( + globalState *GlobalState, + frameEvent *app.FrameEvent, +) NewState { + gtx := app.NewContext(&s.ops, *frameEvent) + for ev, ok := s.editor.Update(gtx); ok; ev, ok = s.editor.Update(gtx) { + log.Debug().Any("Editor event", ev).Send() + } + label := material.H3(globalState.Theme, "Enter timestamp") + hint := material.Subtitle1( + globalState.Theme, + "Format: --
T::(Z|+)", + ) + list := layout.List{Axis: layout.Vertical} + list.Layout(gtx, 3, func(gtx layout.Context, index int) layout.Dimensions { + switch index { + case 0: + return label.Layout(gtx) + case 1: + return hint.Layout(gtx) + case 2: + return s.inputField.Layout(gtx) + default: + return hint.Layout(gtx) + } + }) + frameEvent.Frame(&s.ops) + return NewState{} +} + +func (s *StateEnterTime) handleQuitEvent() NewState { + return NewState{ExitCode: other.IntoPointer(0)} +} diff --git a/windowState.go b/windowState.go new file mode 100644 index 0000000..438b969 --- /dev/null +++ b/windowState.go @@ -0,0 +1,20 @@ +package main + +import ( + "gioui.org/io/event" +) + +type WindowState interface { + Run(globalState *GlobalState, event event.Event) NewState +} + +type NewState struct { + // If null, keep current state + NextState WindowState + Error error + ExitCode *int +} + +func EmptyEvent() NewState { + return NewState{} +}