2023-06-30 14:38:51 -06:00
|
|
|
package tomo
|
|
|
|
|
2024-08-16 15:40:39 -06:00
|
|
|
import "sync"
|
2023-06-30 14:38:51 -06:00
|
|
|
import "image"
|
2023-08-23 23:01:40 -06:00
|
|
|
import "git.tebibyte.media/tomo/tomo/canvas"
|
2023-06-30 14:38:51 -06:00
|
|
|
|
2024-08-16 15:40:39 -06:00
|
|
|
// TODO this really sucks. It might be a good idea to have Do be the entry point
|
|
|
|
// for every off-thread call, and Stop should just call backend.Stop within
|
|
|
|
// backend.Do. This is because Do is a queue and is not vulnerable to recursive
|
|
|
|
// locking.
|
|
|
|
|
|
|
|
var stopping bool
|
|
|
|
var stoppingLock sync.Mutex
|
|
|
|
func isStopping () bool {
|
|
|
|
stoppingLock.Lock()
|
|
|
|
defer stoppingLock.Unlock()
|
|
|
|
return stopping
|
|
|
|
}
|
|
|
|
func setStopping (is bool) {
|
|
|
|
stoppingLock.Lock()
|
|
|
|
defer stoppingLock.Unlock()
|
|
|
|
stopping = is
|
|
|
|
}
|
|
|
|
|
2024-09-11 21:56:12 -06:00
|
|
|
// Stop stops the currently running Backend.
|
2023-06-30 14:38:51 -06:00
|
|
|
func Stop () {
|
2024-08-16 15:40:39 -06:00
|
|
|
if isStopping() { return }
|
|
|
|
setStopping(true)
|
2023-07-15 23:06:24 -06:00
|
|
|
backendLock.Lock()
|
2024-08-13 10:17:54 -06:00
|
|
|
defer backendLock.Unlock()
|
|
|
|
if backend == nil { return }
|
|
|
|
backend.Stop()
|
2023-06-30 14:38:51 -06:00
|
|
|
backend = nil
|
2024-08-16 15:40:39 -06:00
|
|
|
setStopping(false)
|
2023-06-30 14:38:51 -06:00
|
|
|
}
|
|
|
|
|
2023-07-18 19:49:36 -06:00
|
|
|
// Do performs a callback function in the event loop thread as soon as possible.
|
2023-07-15 22:33:44 -06:00
|
|
|
func Do (callback func ()) {
|
2023-07-15 23:06:24 -06:00
|
|
|
backendLock.Lock()
|
2024-08-13 10:17:54 -06:00
|
|
|
defer backendLock.Unlock()
|
2023-07-15 23:06:24 -06:00
|
|
|
if backend != nil { backend.Do(callback) }
|
2023-07-15 22:33:44 -06:00
|
|
|
}
|
|
|
|
|
2024-09-11 21:52:36 -06:00
|
|
|
// NewWindow creates and returns a Window within the specified bounds on screen.
|
2024-09-10 22:54:45 -06:00
|
|
|
func NewWindow (kind WindowKind, bounds image.Rectangle) (Window, error) {
|
2023-06-30 14:38:51 -06:00
|
|
|
assertBackend()
|
2024-09-10 22:54:45 -06:00
|
|
|
return backend.NewWindow(kind, bounds)
|
2023-09-05 11:21:59 -06:00
|
|
|
}
|
|
|
|
|
2023-07-18 19:49:36 -06:00
|
|
|
// NewBox creates and returns a basic Box.
|
2023-06-30 14:38:51 -06:00
|
|
|
func NewBox () Box {
|
|
|
|
assertBackend()
|
|
|
|
return backend.NewBox()
|
|
|
|
}
|
|
|
|
|
2023-07-18 19:49:36 -06:00
|
|
|
// NewTextBox creates and returns a Box that can display text.
|
2023-06-30 14:38:51 -06:00
|
|
|
func NewTextBox () TextBox {
|
|
|
|
assertBackend()
|
|
|
|
return backend.NewTextBox()
|
|
|
|
}
|
|
|
|
|
2023-07-18 19:49:36 -06:00
|
|
|
// NewCanvasBox creates and returns a Box that can display custom graphics.
|
2023-06-30 14:38:51 -06:00
|
|
|
func NewCanvasBox () CanvasBox {
|
|
|
|
assertBackend()
|
|
|
|
return backend.NewCanvasBox()
|
|
|
|
}
|
|
|
|
|
2023-07-18 19:49:36 -06:00
|
|
|
// NewContainerBox creates and returns a Box that can contain other boxes.
|
2023-06-30 14:38:51 -06:00
|
|
|
func NewContainerBox () ContainerBox {
|
|
|
|
assertBackend()
|
|
|
|
return backend.NewContainerBox()
|
|
|
|
}
|
2023-08-20 15:54:06 -06:00
|
|
|
|
2024-09-11 21:52:36 -06:00
|
|
|
// NewTexture creates a new canvas.Texture from an image. When no longer in use,
|
|
|
|
// it must be freed using Close().
|
2023-09-04 10:21:17 -06:00
|
|
|
func NewTexture (source image.Image) canvas.TextureCloser {
|
2023-08-20 15:54:06 -06:00
|
|
|
assertBackend()
|
|
|
|
return backend.NewTexture(source)
|
|
|
|
}
|
2024-06-03 17:29:41 -06:00
|
|
|
|
|
|
|
// NewCanvas creates a new canvas with the specified bounds. When no longer in
|
|
|
|
// use, it must be freed using Close().
|
|
|
|
func NewCanvas (bounds image.Rectangle) canvas.CanvasCloser {
|
|
|
|
assertBackend()
|
2024-06-03 17:32:47 -06:00
|
|
|
return backend.NewCanvas(bounds)
|
2024-06-03 17:29:41 -06:00
|
|
|
}
|