• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / ark-pixel / 13728878286

07 Mar 2025 08:37PM CUT coverage: 89.367%. Remained the same
13728878286

push

github

web-flow
Remove monitors example (#10)

1454 of 1627 relevant lines covered (89.37%)

222401.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.77
/window/window.go
1
package window
2

3
import (
4
        "fmt"
5
        "log"
6

7
        pixel "github.com/gopxl/pixel/v2"
8
        "github.com/gopxl/pixel/v2/backends/opengl"
9
        "github.com/mlange-42/ark-tools/resource"
10
        "github.com/mlange-42/ark/ecs"
11
        "golang.org/x/image/colornames"
12
)
13

14
// Drawer interface.
15
// Drawers are used by the [Window] to render information from an Ark application.
16
type Drawer interface {
17
        // Initialize is called before any other method.
18
        // Use it to initialize the Drawer.
19
        Initialize(w *ecs.World, win *opengl.Window)
20

21
        // Update is called with normal system updates.
22
        // Can be used to update observers.
23
        Update(w *ecs.World)
24

25
        // UpdateInputs is called on every UI update, i.e. with the frequency of FPS.
26
        // Can be used to handle user input of the previous frame update.
27
        UpdateInputs(w *ecs.World, win *opengl.Window)
28

29
        // Draw is called on UI updates, every [Model.DrawInterval] steps.
30
        // Draw is not called when the host window is minimized.
31
        // Do all OpenGL drawing on the window here.
32
        Draw(w *ecs.World, win *opengl.Window)
33
}
34

35
// Bounds define a bounding box for a window.
36
type Bounds struct {
37
        X int // X position
38
        Y int // Y position
39
        W int // Width
40
        H int // Height
41
}
42

43
// B created a new Bounds object.
44
func B(x, y, w, h int) Bounds {
1✔
45
        return Bounds{x, y, w, h}
1✔
46
}
1✔
47

48
// Window provides an OpenGL window for drawing.
49
// Drawing is done by one or more [Drawer] instances.
50
// Further, window bounds and update and draw intervals can be configured.
51
//
52
// If the world contains a resource of type [github.com/mlange-42/ark-tools/resource/Termination],
53
// the model is terminated when the window is closed.
54
type Window struct {
55
        Title        string   // Window title. Optional.
56
        Bounds       Bounds   // Window bounds (position and size). Optional.
57
        Drawers      []Drawer // Drawers in increasing z order.
58
        DrawInterval int      // Interval for re-drawing, in UI frames. Optional.
59
        window       *opengl.Window
60
        drawStep     int64
61
        isClosed     bool
62
        termRes      ecs.Resource[resource.Termination]
63
}
64

65
// With adds one or more [Drawer] instances to the window.
66
func (w *Window) With(drawers ...Drawer) *Window {
2✔
67
        w.Drawers = append(w.Drawers, drawers...)
2✔
68
        return w
2✔
69
}
2✔
70

71
// Initialize the window system.
72
func (w *Window) Initialize(world *ecs.World) {}
1✔
73

74
// InitializeUI the window system.
75
func (w *Window) InitializeUI(world *ecs.World) {
1✔
76
        if w.Bounds.W <= 0 {
2✔
77
                w.Bounds.W = 1024
1✔
78
        }
1✔
79
        if w.Bounds.H <= 0 {
2✔
80
                w.Bounds.H = 768
1✔
81
        }
1✔
82
        if w.Title == "" {
2✔
83
                w.Title = "Ark"
1✔
84
        }
1✔
85
        cfg := opengl.WindowConfig{
1✔
86
                Title:     w.Title,
1✔
87
                Bounds:    pixel.R(0, 0, float64(w.Bounds.W), float64(w.Bounds.H)),
1✔
88
                Position:  pixel.V(float64(w.Bounds.X), float64(w.Bounds.Y)),
1✔
89
                Resizable: true,
1✔
90
        }
1✔
91

1✔
92
        defer func() {
2✔
93
                if err := recover(); err != nil {
1✔
94
                        txt := fmt.Sprint(err)
×
95
                        if txt == "mainthread: did not call Run" {
×
96
                                log.Fatal("ERROR: when using graphics via the pixel engine, run the app like this:\n    window.Run(app)")
×
97
                        }
×
98
                        panic(err)
×
99
                }
100
        }()
101

102
        var err error
1✔
103
        w.window, err = opengl.NewWindow(cfg)
1✔
104
        if err != nil {
1✔
105
                panic(err)
×
106
        }
107
        for _, d := range w.Drawers {
2✔
108
                d.Initialize(world, w.window)
1✔
109
        }
1✔
110

111
        w.termRes = ecs.NewResource[resource.Termination](world)
1✔
112
        w.drawStep = 0
1✔
113
        w.isClosed = false
1✔
114
}
115

116
// Update the window system.
117
func (w *Window) Update(world *ecs.World) {
100✔
118
        if w.isClosed {
100✔
119
                return
×
120
        }
×
121
        for _, d := range w.Drawers {
200✔
122
                d.Update(world)
100✔
123
        }
100✔
124
}
125

126
// UpdateUI the window system.
127
func (w *Window) UpdateUI(world *ecs.World) {
100✔
128
        if w.window.Closed() {
100✔
129
                if !w.isClosed {
×
130
                        term := w.termRes.Get()
×
131
                        if term != nil {
×
132
                                term.Terminate = true
×
133
                        }
×
134
                        w.isClosed = true
×
135
                }
136
                return
×
137
        }
138
        if !w.isMinimized() && (w.DrawInterval <= 1 || w.drawStep%int64(w.DrawInterval) == 0) {
200✔
139
                w.window.Clear(colornames.Black)
100✔
140

100✔
141
                for _, d := range w.Drawers {
200✔
142
                        d.Draw(world, w.window)
100✔
143
                }
100✔
144
        }
145
        w.drawStep++
100✔
146
}
147

148
func (w *Window) isMinimized() bool {
100✔
149
        b := w.window.Bounds()
100✔
150
        return b.W() <= 0 || b.H() <= 0
100✔
151
}
100✔
152

153
// PostUpdateUI updates the underlying GL window and input events.
154
func (w *Window) PostUpdateUI(world *ecs.World) {
100✔
155
        w.window.Update()
100✔
156
        for _, d := range w.Drawers {
200✔
157
                d.UpdateInputs(world, w.window)
100✔
158
        }
100✔
159
}
160

161
// Finalize the window system.
162
func (w *Window) Finalize(world *ecs.World) {}
1✔
163

164
// FinalizeUI the window system.
165
func (w *Window) FinalizeUI(world *ecs.World) {
1✔
166
        w.window.Destroy()
1✔
167
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc