Compare commits

...

13 Commits

9 changed files with 45 additions and 156 deletions

View File

@@ -1,6 +1,5 @@
# tomo
WIP rewrite of tomo.
[![Go Reference](https://pkg.go.dev/badge/git.tebibyte.media/tomo/tomo.svg)](https://pkg.go.dev/git.tebibyte.media/tomo/tomo)
This module will serve as a wafer-thin collection of interfaces and glue code so
that plugins will be an actual viable concept.
Tomo is a lightweight GUI toolkit written in pure Go.

View File

@@ -1,113 +0,0 @@
package tomo
import "image"
// Application represents an application object.
type Application interface {
// Describe returns a description of the application.
Describe () ApplicationDescription
// Init performs the initial setup of the application.
Init ()
}
// ApplicationDescription describes the name and type of an application.
type ApplicationDescription struct {
// The name or ID of the application.
Name string
// Role describes what the application does.
Role ApplicationRole
}
// String satisfies the fmt.Stringer interface.
func (application ApplicationDescription) String () string {
if application.Name == "" {
return application.Role.String()
} else {
return application.Name
}
}
// ApplicationRole describes what an application does.
type ApplicationRole int; const (
RoleUnknown ApplicationRole = iota
RoleWebBrowser
RoleMesssanger
RolePhone
RoleMail
RoleTerminalEmulator
RoleFileBrowser
RoleTextEditor
RoleDocumentViewer
RoleWordProcessor
RoleSpreadsheet
RoleSlideshow
RoleCalculator
RolePreferences
RoleProcessManager
RoleSystemInformation
RoleManual
RoleCamera
RoleImageViewer
RoleMediaPlayer
RoleImageEditor
RoleAudioEditor
RoleVideoEditor
RoleClock
RoleCalendar
RoleChecklist
)
// String satisfies the fmt.Stringer interface.
func (role ApplicationRole) String () string {
switch role {
case RoleWebBrowser: return "Web Browser"
case RoleMesssanger: return "Messsanger"
case RolePhone: return "Phone"
case RoleMail: return "Mail"
case RoleTerminalEmulator: return "Terminal Emulator"
case RoleFileBrowser: return "File Browser"
case RoleTextEditor: return "Text Editor"
case RoleDocumentViewer: return "Document Viewer"
case RoleWordProcessor: return "Word Processor"
case RoleSpreadsheet: return "Spreadsheet"
case RoleSlideshow: return "Slideshow"
case RoleCalculator: return "Calculator"
case RolePreferences: return "Preferences"
case RoleProcessManager: return "Process Manager"
case RoleSystemInformation: return "System Information"
case RoleManual: return "Manual"
case RoleCamera: return "Camera"
case RoleImageViewer: return "Image Viewer"
case RoleMediaPlayer: return "Media Player"
case RoleImageEditor: return "Image Editor"
case RoleAudioEditor: return "Audio Editor"
case RoleVideoEditor: return "Video Editor"
case RoleClock: return "Clock"
case RoleCalendar: return "Calendar"
case RoleChecklist: return "Checklist"
default: return "unknown"
}
}
// RunApplication is like Run, but runs an application.
func RunApplication (application Application) error {
return Run(application.Init)
}
// NewApplicationWindow creates a window for an application. It will
// automatically set window information to signal to the OS that the window is
// owned by the application.
func NewApplicationWindow (application Application, bounds image.Rectangle) (Window, error) {
window, err := NewWindow(bounds)
if err != nil { return nil, err }
window.SetTitle(application.Describe().String())
return window, nil
}

View File

@@ -11,15 +11,22 @@ import "git.tebibyte.media/tomo/tomo/canvas"
type Backend interface {
// These methods create new objects. The backend must reject any object
// that was not made by it.
NewWindow (image.Rectangle) (MainWindow, error)
NewBox () Box
NewTextBox () TextBox
NewCanvasBox () CanvasBox
NewContainerBox () ContainerBox
// NewWindow creates a normal MainWindow and returns it.
NewWindow (image.Rectangle) (MainWindow, error)
// NewPlainWindow creates an undecorated window that does not appear in
// window lists and returns it. This is intended for making things like
// panels, docks, etc.
NewPlainWindow (image.Rectangle) (MainWindow, error)
// NewTexture creates a new texture from an image. The backend must
// reject any texture that was not made by it.
NewTexture (image.Image) canvas.Texture
NewTexture (image.Image) canvas.TextureCloser
// Run runs the event loop until Stop() is called, or the backend
// experiences a fatal error.

View File

@@ -5,28 +5,16 @@ import "image"
// Texture is a handle that points to a 2D raster image managed by the backend.
type Texture interface {
io.Closer
image.Image
// Clip returns a smaller section of this texture, pointing to the same
// internal data. Becaue of this, closing a clipped section will close
// the original texture as well.
// internal data.
Clip (image.Rectangle) Texture
// Bounds returns the size of this texture.
Bounds () image.Rectangle
}
type protectedTexture struct {
// TextureCloser is a texture that can be closed. Anything that receives a
// TextureCloser must close it after use.
type TextureCloser interface {
Texture
}
func (protectedTexture) Close () error {
return nil
}
// Protect makes the Close() method of a texture do nothing. This is useful if
// several of the same texture are given out to different objects, but only one
// has the responsibility of closing it.
func Protect (texture Texture) Texture {
return protectedTexture { Texture: texture }
io.Closer
}

View File

@@ -216,7 +216,7 @@ type ContentBox interface {
// vertically.
SetAlign (x, y Align)
// ContentBounds returns the bounds of the inner content of the Box
// relative to the window.
// relative to the Box's InnerBounds.
ContentBounds () image.Rectangle
// ScrollTo shifts the origin of the Box's content to the origin of the
// Box's InnerBounds, offset by the given point.
@@ -258,11 +258,6 @@ type TextBox interface {
type ContainerBox interface {
ContentBox
// SetPropagateEvents specifies whether or not child Objects will
// receive user input events. It is true by default. If it is false, all
// user input that would otherwise be directed to a child Box is
// directed to this Box.
SetPropagateEvents (bool)
// SetGap sets the gap between child Objects.
SetGap (image.Point)
// Add appends a child Object.
@@ -275,13 +270,22 @@ type ContainerBox interface {
Insert (child Object, before Object)
// Clear removes all child Objects.
Clear ()
// Length returns the amount of child objects.
// Length returns the amount of child Objects.
Length () int
// At returns the child Object at the specified index.
At (int) Object
// SetLayout sets the layout of this Box. Child Objects will be
// positioned according to it.
SetLayout (Layout)
// These methods control whether certain user input events get
// propagated to child Objects. If set to true, the relevant events will
// be sent to this container. If set to false (which is the default),
// the events will be sent to the appropriate child Object.
CaptureDND (bool)
CaptureMouse (bool)
CaptureScroll (bool)
CaptureKeyboard (bool)
}
// LayoutHints are passed to a layout to tell it how to arrange child boxes.

View File

@@ -1,6 +1,5 @@
package theme
import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/tomo/data"
import "git.tebibyte.media/tomo/tomo/canvas"
@@ -73,6 +72,7 @@ type Icon int; const (
// devices
IconDevice // generic
IconRouter
IconSwitch
IconServer
IconDesktop
IconLaptop
@@ -429,12 +429,3 @@ func MimeIcon (mime data.Mime, size IconSize) canvas.Texture {
if current == nil { return nil }
return current.MimeIcon(mime, size)
}
// ApplicationIcon describes the icon of the application.
type ApplicationIcon tomo.ApplicationDescription
// Texture returns a texture of the corresponding icon ID.
func (icon ApplicationIcon) Texture (size IconSize) canvas.Texture {
if current == nil { return nil }
return current.ApplicationIcon(icon, size)
}

View File

@@ -92,8 +92,9 @@ type Theme interface {
// MimeIcon returns an icon corresponding to a MIME type.
MimeIcon (data.Mime, IconSize) canvas.Texture
// ApplicationIcon returns an icon corresponding to an application.
ApplicationIcon (ApplicationIcon, IconSize) canvas.Texture
// ApplicationIcon returns an icon corresponding to an application's
// name. This may return nil if there is no icon for that application.
ApplicationIcon (string, IconSize) canvas.Texture
}
var current Theme

10
tomo.go
View File

@@ -57,6 +57,14 @@ func NewWindow (bounds image.Rectangle) (MainWindow, error) {
return backend.NewWindow(bounds)
}
// NewPlainWindow is like NewWindow, but it creates an undecorated window that
// does not appear in window lists. It is intended for creating things like
// docks, panels, etc.
func NewPlainWindow (bounds image.Rectangle) (MainWindow, error) {
assertBackend()
return backend.NewPlainWindow(bounds)
}
// NewBox creates and returns a basic Box.
func NewBox () Box {
assertBackend()
@@ -83,7 +91,7 @@ func NewContainerBox () ContainerBox {
// NewTexture creates a new texture from an image. When no longer in use, it
// must be freed using Close().
func NewTexture (source image.Image) canvas.Texture {
func NewTexture (source image.Image) canvas.TextureCloser {
assertBackend()
return backend.NewTexture(source)
}

View File

@@ -6,6 +6,8 @@ import "os"
import "strings"
import "path/filepath"
var userDataDir string
func init () {
pathVariable := os.Getenv("TOMO_PLUGIN_PATH")
pluginPaths = strings.Split(pathVariable, ":")
@@ -19,4 +21,6 @@ func init () {
pluginPaths,
filepath.Join(homeDir, ".local/lib/tomo/plugins"))
}
userDataDir = filepath.Join(homeDir, ".local/share")
}