Skip to content

Commit 0f4b762

Browse files
authored
Merge pull request #932 from gucio321/backend-abstraction-layer
Backend abstraction layer
2 parents cfac4b4 + b753ede commit 0f4b762

File tree

3 files changed

+110
-48
lines changed

3 files changed

+110
-48
lines changed

Backend.go

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package giu
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/AllenDang/cimgui-go/backend"
7+
"github.com/AllenDang/cimgui-go/backend/glfwbackend"
8+
)
9+
10+
// sometimes we need to tell what we mean ;-)
11+
// good example is:
12+
// FlagsNotResizable in giu,
13+
// but cimgui-go has only FlagsResizable. So SetFlags(Resizable, 0).
14+
type flagValue[T ~int] struct {
15+
flag T
16+
value int
17+
}
18+
19+
// GIUBackend is an abstraction layer between cimgui-go's Backends.
20+
//
21+
//nolint:revive // this name is OK
22+
type GIUBackend backend.Backend[MasterWindowFlags]
23+
24+
var _ GIUBackend = &GLFWBackend{}
25+
26+
// GLFWBackend is an implementation of glfbackend.GLFWBackend cimgui-go backend with respect to
27+
// giu's MasterWIndowFlags.
28+
type GLFWBackend struct {
29+
*glfwbackend.GLFWBackend
30+
}
31+
32+
// NewGLFWBackend creates a new instance of GLFWBackend.
33+
func NewGLFWBackend() *GLFWBackend {
34+
return &GLFWBackend{
35+
GLFWBackend: glfwbackend.NewGLFWBackend(),
36+
}
37+
}
38+
39+
// SetInputMode implements backend.Backend interface.
40+
func (b *GLFWBackend) SetInputMode(mode, _ MasterWindowFlags) {
41+
flag := b.parseFlag(mode)
42+
b.GLFWBackend.SetInputMode(flag.flag, glfwbackend.GLFWWindowFlags(flag.value))
43+
}
44+
45+
// SetSwapInterval implements backend.Backend interface.
46+
func (b *GLFWBackend) SetSwapInterval(interval MasterWindowFlags) error {
47+
intervalV := b.parseFlag(interval).flag
48+
if err := b.GLFWBackend.SetSwapInterval(intervalV); err != nil {
49+
return fmt.Errorf("giu.GLFWBackend got error while SwapInterval: %w", err)
50+
}
51+
52+
return nil
53+
}
54+
55+
// SetWindowFlags implements backend.Backend interface.
56+
func (b *GLFWBackend) SetWindowFlags(flags MasterWindowFlags, _ int) {
57+
flag := b.parseFlag(flags)
58+
b.GLFWBackend.SetWindowFlags(flag.flag, flag.value)
59+
}
60+
61+
func (b *GLFWBackend) parseFlag(m MasterWindowFlags) flagValue[glfwbackend.GLFWWindowFlags] {
62+
data := map[MasterWindowFlags]flagValue[glfwbackend.GLFWWindowFlags]{
63+
MasterWindowFlagsNotResizable: {glfwbackend.GLFWWindowFlagsResizable, 0},
64+
MasterWindowFlagsMaximized: {glfwbackend.GLFWWindowFlagsMaximized, 1},
65+
MasterWindowFlagsFloating: {glfwbackend.GLFWWindowFlagsFloating, 1},
66+
MasterWindowFlagsFrameless: {glfwbackend.GLFWWindowFlagsDecorated, 0},
67+
MasterWindowFlagsTransparent: {glfwbackend.GLFWWindowFlagsTransparent, 1},
68+
MasterWindowFlagsHidden: {glfwbackend.GLFWWindowFlagsVisible, 0},
69+
}
70+
71+
d, ok := data[m]
72+
Assert(ok, "GLFWBackend", "parseFlag", "Unknown MasterWindowFlags")
73+
74+
return d
75+
}

Context.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import (
44
"fmt"
55
"sync"
66

7-
"github.com/AllenDang/cimgui-go/backend"
8-
"github.com/AllenDang/cimgui-go/backend/glfwbackend"
97
"github.com/AllenDang/cimgui-go/imgui"
108
"gopkg.in/eapache/queue.v1"
119
)
@@ -51,7 +49,7 @@ type state struct {
5149
//
5250
//nolint:revive // I WANT TO CALL THIS GIUContext!
5351
type GIUContext struct {
54-
backend backend.Backend[glfwbackend.GLFWWindowFlags]
52+
backend GIUBackend
5553

5654
isRunning bool
5755

@@ -79,7 +77,7 @@ type GIUContext struct {
7977
}
8078

8179
// CreateContext creates a new giu context.
82-
func CreateContext(b backend.Backend[glfwbackend.GLFWWindowFlags]) *GIUContext {
80+
func CreateContext(b GIUBackend) *GIUContext {
8381
result := GIUContext{
8482
cssStylesheet: make(cssStylesheet),
8583
backend: b,
@@ -148,7 +146,7 @@ func (c *GIUContext) cleanStates() {
148146
}
149147

150148
// Backend returns the imgui.backend used by the context.
151-
func (c *GIUContext) Backend() backend.Backend[glfwbackend.GLFWWindowFlags] {
149+
func (c *GIUContext) Backend() GIUBackend {
152150
return c.backend
153151
}
154152

MasterWindow.go

+32-43
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,6 @@ const (
3636
)
3737

3838
// parseAndApply converts MasterWindowFlags to appropriate glfwbackend.GLFWWindowFlags.
39-
func (m MasterWindowFlags) parseAndApply(b backend.Backend[glfwbackend.GLFWWindowFlags]) {
40-
data := map[MasterWindowFlags]struct {
41-
f glfwbackend.GLFWWindowFlags
42-
value int // value isn't always true (sometimes false). Also WindowHint takes int not bool
43-
}{
44-
MasterWindowFlagsNotResizable: {glfwbackend.GLFWWindowFlagsResizable, 0},
45-
MasterWindowFlagsMaximized: {glfwbackend.GLFWWindowFlagsMaximized, 1},
46-
MasterWindowFlagsFloating: {glfwbackend.GLFWWindowFlagsFloating, 1},
47-
MasterWindowFlagsFrameless: {glfwbackend.GLFWWindowFlagsDecorated, 0},
48-
MasterWindowFlagsTransparent: {glfwbackend.GLFWWindowFlagsTransparent, 1},
49-
MasterWindowFlagsHidden: {glfwbackend.GLFWWindowFlagsVisible, 0},
50-
}
51-
52-
for flag, d := range data {
53-
if m&flag != 0 {
54-
b.SetWindowFlags(d.f, d.value)
55-
}
56-
}
57-
}
5839

5940
// TODO(gucio321) implement this in cimgui-go
6041
// DontCare could be used as an argument to (*MasterWindow).SetSizeLimits.
@@ -63,7 +44,9 @@ func (m MasterWindowFlags) parseAndApply(b backend.Backend[glfwbackend.GLFWWindo
6344
// MasterWindow represents a glfw master window
6445
// It is a base for a windows (see Window.go).
6546
type MasterWindow struct {
66-
backend backend.Backend[glfwbackend.GLFWWindowFlags]
47+
// generally Context should be used instead but as I don't like global
48+
// variables, I prefer to keep a pointer here and refer it as possible.
49+
ctx *GIUContext
6750

6851
width int
6952
height int
@@ -96,7 +79,7 @@ func NewMasterWindow(title string, width, height int, flags MasterWindowFlags) *
9679
// Disable imgui.ini
9780
io.SetIniFilename("")
9881

99-
currentBackend, err := backend.CreateBackend(glfwbackend.NewGLFWBackend())
82+
currentBackend, err := backend.CreateBackend(NewGLFWBackend())
10083
if err != nil && !errors.Is(err, backend.CExposerError) {
10184
panic(err)
10285
}
@@ -111,18 +94,24 @@ func NewMasterWindow(title string, width, height int, flags MasterWindowFlags) *
11194
title: title,
11295
io: io,
11396
context: imGuiContext,
114-
backend: currentBackend,
97+
ctx: Context,
11598
}
11699

117100
currentBackend.SetBeforeRenderHook(mw.beforeRender)
118101
currentBackend.SetAfterRenderHook(mw.afterRender)
119102
currentBackend.SetBeforeDestroyContextHook(mw.beforeDestroy)
120-
flags.parseAndApply(currentBackend)
103+
104+
for f := MasterWindowFlagsNotResizable; f <= MasterWindowFlagsHidden; f <<= 1 {
105+
if f&flags != 0 {
106+
currentBackend.SetWindowFlags(f, 0) // 0 because it is not used anyway (flag values are determined by giu
107+
}
108+
}
109+
121110
currentBackend.CreateWindow(title, width, height)
122111

123112
mw.SetInputHandler(newInputHandler())
124113

125-
mw.backend.SetSizeChangeCallback(mw.sizeChange)
114+
mw.ctx.backend.SetSizeChangeCallback(mw.sizeChange)
126115

127116
mw.SetBgColor(colornames.Black)
128117

@@ -279,8 +268,8 @@ func (w *MasterWindow) Run(loopFunc func()) {
279268

280269
// GetSize return size of master window.
281270
func (w *MasterWindow) GetSize() (width, height int) {
282-
if w.backend != nil {
283-
w, h := w.backend.DisplaySize()
271+
if w.ctx.backend != nil {
272+
w, h := w.ctx.backend.DisplaySize()
284273
return int(w), int(h)
285274
}
286275

@@ -299,36 +288,36 @@ func (w *MasterWindow) SetBgColor(bgColor color.Color) {
299288
W: float32(a) / mask,
300289
}
301290

302-
w.backend.SetBgColor(w.clearColor)
291+
w.ctx.backend.SetBgColor(w.clearColor)
303292
}
304293

305294
// SetTargetFPS sets target FPS of master window.
306295
// Default for GLFW is 30.
307296
func (w *MasterWindow) SetTargetFPS(fps uint) {
308-
w.backend.SetTargetFPS(fps)
297+
w.ctx.backend.SetTargetFPS(fps)
309298
}
310299

311300
// GetPos return position of master window.
312301
func (w *MasterWindow) GetPos() (x, y int) {
313302
var xResult, yResult int32
314-
if w.backend != nil {
315-
xResult, yResult = w.backend.GetWindowPos()
303+
if w.ctx.backend != nil {
304+
xResult, yResult = w.ctx.backend.GetWindowPos()
316305
}
317306

318307
return int(xResult), int(yResult)
319308
}
320309

321310
// SetPos sets position of master window.
322311
func (w *MasterWindow) SetPos(x, y int) {
323-
if w.backend != nil {
324-
w.backend.SetWindowPos(x, y)
312+
if w.ctx.backend != nil {
313+
w.ctx.backend.SetWindowPos(x, y)
325314
}
326315
}
327316

328317
// SetSize sets size of master window.
329318
func (w *MasterWindow) SetSize(x, y int) {
330-
if w.backend != nil {
331-
w.backend.SetWindowSize(x, y)
319+
if w.ctx.backend != nil {
320+
w.ctx.backend.SetWindowSize(x, y)
332321
}
333322
}
334323

@@ -342,14 +331,14 @@ func (w *MasterWindow) SetSize(x, y int) {
342331
// Mac OS X: Selecting Quit from the application menu will trigger the close
343332
// callback for all windows.
344333
func (w *MasterWindow) SetCloseCallback(cb func() bool) {
345-
w.backend.SetCloseCallback(func() {
346-
w.backend.SetShouldClose(cb())
334+
w.ctx.backend.SetCloseCallback(func() {
335+
w.ctx.backend.SetShouldClose(cb())
347336
})
348337
}
349338

350339
// SetDropCallback sets callback when file was dropped into the window.
351340
func (w *MasterWindow) SetDropCallback(cb func([]string)) {
352-
w.backend.SetDropCallback(cb)
341+
w.ctx.backend.SetDropCallback(cb)
353342
}
354343

355344
// RegisterKeyboardShortcuts registers a global - master window - keyboard shortcuts.
@@ -379,7 +368,7 @@ func (w *MasterWindow) RegisterKeyboardShortcuts(s ...WindowShortcut) *MasterWin
379368
// The desired image sizes varies depending on platform and system settings. The selected
380369
// images will be rescaled as needed. Good sizes include 16x16, 32x32 and 48x48.
381370
func (w *MasterWindow) SetIcon(icons ...image.Image) {
382-
w.backend.SetIcons(icons...)
371+
w.ctx.backend.SetIcons(icons...)
383372
}
384373

385374
// SetSizeLimits sets the size limits of the client area of the specified window.
@@ -389,30 +378,30 @@ func (w *MasterWindow) SetIcon(icons ...image.Image) {
389378
// To specify only a minimum size or only a maximum one, set the other pair to giu.DontCare.
390379
// To disable size limits for a window, set them all to giu.DontCare.
391380
func (w *MasterWindow) SetSizeLimits(minw, minh, maxw, maxh int) {
392-
w.backend.SetWindowSizeLimits(minw, minh, maxw, maxh)
381+
w.ctx.backend.SetWindowSizeLimits(minw, minh, maxw, maxh)
393382
}
394383

395384
// SetTitle updates master window's title.
396385
func (w *MasterWindow) SetTitle(title string) {
397-
w.backend.SetWindowTitle(title)
386+
w.ctx.backend.SetWindowTitle(title)
398387
}
399388

400389
// Close will safely close the master window.
401390
func (w *MasterWindow) Close() {
402-
w.SetShouldClose(true)
391+
w.ctx.backend.SetShouldClose(true)
403392
}
404393

405394
// SetShouldClose sets whether master window should be closed.
406395
func (w *MasterWindow) SetShouldClose(v bool) {
407-
w.backend.SetShouldClose(v)
396+
w.ctx.backend.SetShouldClose(v)
408397
}
409398

410399
// SetInputHandler allows to change default input handler.
411400
// see InputHandler.go.
412401
func (w *MasterWindow) SetInputHandler(handler InputHandler) {
413402
Context.InputHandler = handler
414403

415-
w.backend.SetKeyCallback(func(key, _, action, modifier int) {
404+
w.ctx.backend.SetKeyCallback(func(key, _, action, modifier int) {
416405
k, m, a := keyFromGLFWKey(glfwbackend.GLFWKey(key)), Modifier(modifier), Action(action)
417406
handler.Handle(k, m, a)
418407

0 commit comments

Comments
 (0)