Compare commits

...

39 Commits

Author SHA1 Message Date
Sasha Koshka 9a5b4ee7e8 Add home icon 2024-05-05 02:53:07 -04:00
Sasha Koshka 3e561d7bf0 Fix wording of theme.Theme doc comment 2024-05-03 13:46:50 -04:00
Sasha Koshka b96e8f744f Namespace icon IDs 2024-05-03 13:21:35 -04:00
Sasha Koshka 9aa6f2900e Added application role icons 2024-05-03 13:10:44 -04:00
Sasha Koshka a3fc0ce66d Remove ApplicationIcon from Theme
Since Icon can now take in arbitrary strings, we can just have it
serve application icons as well.
2024-05-03 13:08:14 -04:00
Sasha Koshka 65bf341514 Icon IDs are now strings 2024-05-03 13:07:27 -04:00
Sasha Koshka 042f2f0131 Completely remove plugin system
Plugins may be moved to Nasin
2024-04-30 13:12:34 -04:00
Sasha Koshka 4fd5e54e42 Add editorconfig 2024-04-29 16:23:46 -04:00
Sasha Koshka 9a9e546b37 Remove application framework stuff 2024-04-29 00:39:17 -04:00
Sasha Koshka a2a5c16e38 Changed the semantics of ContentBounds 2023-09-14 14:47:33 -04:00
Sasha Koshka 28cd889254 Removed tiler for now, needs to be rethought a bit 2023-09-08 20:57:15 -04:00
Sasha Koshka e682fdd9d8 Add icon for switch 2023-09-08 20:57:00 -04:00
Sasha Koshka 9719391e5d NewApplicationWindow returns MainWindow nows 2023-09-08 16:29:03 -04:00
Sasha Koshka 8a531986eb What??? 2023-09-07 18:25:35 -04:00
Sasha Koshka c3c6ff61f5 Add Tiler interface 2023-09-05 18:14:36 -04:00
Sasha Koshka 89f7bf47ce Add ability to create an undecorated window 2023-09-05 13:21:59 -04:00
Sasha Koshka bebd58dac1 Added event capturing to containers 2023-09-05 13:10:35 -04:00
Sasha Koshka f9a85fd949 Added filesystems for application data 2023-09-04 13:48:03 -04:00
Sasha Koshka 6ac653adb6 Made ownership of textures more explicit 2023-09-04 12:21:17 -04:00
Sasha Koshka 7b28419432 Texture must now implement Image 2023-09-04 12:07:29 -04:00
Sasha Koshka 57e6a9ff21 lolll whoops 2023-09-04 02:56:00 -04:00
Sasha Koshka a06f94e41b Added support for defining applications as objects 2023-09-04 02:26:21 -04:00
Sasha Koshka 4d157756eb Added a String method to a bunch of stuff 2023-09-04 01:47:03 -04:00
Sasha Koshka 63a67e40d1 Added a Bounds() method to Texture 2023-09-04 01:28:04 -04:00
Sasha Koshka b629b4eb4e Cleared up wording around theme textures 2023-08-29 15:52:07 -04:00
Sasha Koshka 7510047ef3 Fix package name errors in theme 2023-08-24 16:30:10 -04:00
Sasha Koshka fdea479ee7 Textures have been moved to the canvas module 2023-08-24 01:01:40 -04:00
Sasha Koshka dc31de0ecb Textures are now actually used 2023-08-23 18:04:54 -04:00
Sasha Koshka a8d5a64837 Added SetTexture on Object 2023-08-21 21:52:51 -04:00
Sasha Koshka 50697e4369 All icons now return textures 2023-08-20 18:41:46 -04:00
Sasha Koshka 3614979e35 Add a function to protect textures 2023-08-20 18:33:20 -04:00
Sasha Koshka 5f5b928528 Icons now use textures 2023-08-20 18:28:30 -04:00
Sasha Koshka b62b846745 AhhhahsdjashdMerge branch 'main' of git.tebibyte.media:tomo/tomo 2023-08-20 17:58:45 -04:00
Sasha Koshka 35c6e167be Added a texture interface 2023-08-20 17:54:06 -04:00
Sasha Koshka 6ced7d1372 Fixed syntax errors 2023-08-12 00:56:13 -04:00
Sasha Koshka e259f122c7 Added an icon API 2023-08-12 00:51:16 -04:00
Sasha Koshka 8e25397a05 Theme roles now have a variant field 2023-08-10 17:49:22 -04:00
Sasha Koshka 2884604fdd Renamed Object.Box to GetBox to resolve naming conflicts 2023-08-10 17:48:40 -04:00
Sasha Koshka f99d9e0d2a Upgrade x/image 2023-08-09 20:55:46 -04:00
13 changed files with 415 additions and 102 deletions

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = 8
charset = utf-8
[*.md]
indent_style = space
indent_size = 2

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

@ -3,6 +3,7 @@ package tomo
import "sort"
import "image"
import "errors"
import "git.tebibyte.media/tomo/tomo/canvas"
// Backend is any Tomo implementation. Backends handle window creation, layout,
// rendering, and events so that there can be as many platform-specific
@ -10,12 +11,23 @@ import "errors"
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.TextureCloser
// Run runs the event loop until Stop() is called, or the backend
// experiences a fatal error.
Run () error

View File

@ -44,8 +44,9 @@ type Pen interface {
StrokeWeight (int) // how thick the stroke is
StrokeAlign (StrokeAlign) // where the stroke is drawn
Stroke (color.Color) // Sets the stroke to a solid color
Fill (color.Color) // Sets the fill to a solid color
Stroke (color.Color) // Sets the stroke to a solid color
Fill (color.Color) // Sets the fill to a solid color
Texture (Texture) // Overlaps a texture onto the fill color
}
// Canvas is an image that supports drawing paths.

20
canvas/texture.go Normal file
View File

@ -0,0 +1,20 @@
package canvas
import "io"
import "image"
// Texture is a handle that points to a 2D raster image managed by the backend.
type Texture interface {
image.Image
// Clip returns a smaller section of this texture, pointing to the same
// internal data.
Clip (image.Rectangle) Texture
}
// TextureCloser is a texture that can be closed. Anything that receives a
// TextureCloser must close it after use.
type TextureCloser interface {
Texture
io.Closer
}

2
go.mod
View File

@ -2,4 +2,4 @@ module git.tebibyte.media/tomo/tomo
go 1.20
require golang.org/x/image v0.8.0
require golang.org/x/image v0.11.0

3
go.sum
View File

@ -3,6 +3,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/image v0.8.0 h1:agUcRXV/+w6L9ryntYYsF2x9fQTMd4T8fiiYXAVW6Jg=
golang.org/x/image v0.8.0/go.mod h1:PwLxp3opCYg4WR2WO9P0L6ESnsD6bLTWcw8zanLMVFM=
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -26,6 +28,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@ -104,7 +104,7 @@ type Align int; const (
// Object is any obscreen object. Each object must be linked to a box, even if
// it is that box.
type Object interface {
Box () Box
GetBox () Box
}
// Box is a basic styled box.
@ -132,6 +132,10 @@ type Box interface {
SetBounds (image.Rectangle)
// SetColor sets the background color of this Box.
SetColor (color.Color)
// SetTexture sets a repeating background texture. If the texture is
// transparent, it will be overlayed atop the color specified by
// SetColor().
SetTexture (canvas.Texture)
// SetBorder sets the Border(s) of the box. The first Border will be the
// most outset, and the last Border will be the most inset.
SetBorder (...Border)
@ -212,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.
@ -254,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.
@ -271,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,55 +0,0 @@
package tomo
import "os"
import "plugin"
import "path/filepath"
var pluginPaths []string
func loadPlugins () {
for _, dir := range pluginPaths {
if dir != "" {
loadPluginsFrom(dir)
}
}
}
func loadPluginsFrom (dir string) {
entries, err := os.ReadDir(dir)
// its no big deal if one of the dirs doesn't exist
if err != nil { return }
for _, entry := range entries {
if entry.IsDir() { continue }
if filepath.Ext(entry.Name()) != ".so" { continue }
pluginPath := filepath.Join(dir, entry.Name())
loadPlugin(pluginPath)
}
}
func loadPlugin (path string) {
die := func (reason string) {
println("tomo: could not load plugin at", path + ":", reason)
}
plugin, err := plugin.Open(path)
if err != nil {
die(err.Error())
return
}
// check for and obtain basic plugin functions
name, ok := extract[func () string](plugin, "Name")
if !ok { die("does not implement Name() string"); return }
_, ok = extract[func () string](plugin, "Description")
if !ok { die("does not implement Description() string"); return }
println("tomo: loaded plugin", name())
}
func extract[T any] (plugin *plugin.Plugin, name string) (value T, ok bool) {
symbol, err := plugin.Lookup(name)
if err != nil { return }
value, ok = symbol.(T)
return
}

278
theme/icon.go Normal file
View File

@ -0,0 +1,278 @@
package theme
import "git.tebibyte.media/tomo/tomo/data"
import "git.tebibyte.media/tomo/tomo/canvas"
// IconSize represents the size of an icon.
type IconSize int; const (
IconSizeSmall IconSize = iota;
IconSizeMedium
IconSizeLarge
)
// String satisfies the fmt.Stringer interface.
func (size IconSize) String () string {
switch size {
case IconSizeSmall: return "small"
case IconSizeMedium: return "medium"
case IconSizeLarge: return "large"
default: return "unknown"
}
}
// Icon represents an icon ID.
type Icon string
// A list of standard icon IDs.
const (
IconUnknown Icon = ""
// objects: files
IconFile Icon = "File" // generic
IconDirectory Icon = "Directory"
IconDirectoryFull Icon = "DirectoryFull"
// objects: places
IconPlaceHome Icon = "PlaceHome"
IconPlaceDownloads Icon = "PlaceDownloads"
IconPlacePhotos Icon = "PlacePhotos"
IconPlaceBooks Icon = "PlaceBooks"
IconPlaceDocuments Icon = "PlaceDocuments"
IconPlaceRepositories Icon = "PlaceRepositories"
IconPlaceMusic Icon = "PlaceMusic"
IconPlaceArchives Icon = "PlaceArchives"
IconPlaceFonts Icon = "PlaceFonts"
IconPlaceBinaries Icon = "PlaceBinaries"
IconPlaceVideos Icon = "PlaceVideos"
IconPlace3DObjects Icon = "Place3DObjects"
IconPlaceHistory Icon = "PlaceHistory"
IconPlacePreferences Icon = "PlacePreferences"
// objects: storage
IconStorage Icon = "Storage" // generic
IconStorageMagneticTape Icon = "StorageMagneticTape"
IconStorageFloppyDisk Icon = "StorageFloppyDisk"
IconStorageHardDisk Icon = "StorageHardDisk"
IconStorageSolidStateDisk Icon = "StorageSolidState"
IconStorageFlashStick Icon = "StorageFlashStick"
IconStorageFlashCard Icon = "StorageFlashCard"
IconStorageROM Icon = "StorageROM"
IconStorageRAM Icon = "StorageRAM"
IconStorageCD Icon = "StorageCD"
IconStorageDVD Icon = "StorageDVD"
// objects: applications
// Keep these in sync with nasin.ApplicationRole!
IconApplication Icon = "Application" // generic
IconApplicationWebBrowser Icon = "ApplicationWebBrowser"
IconApplicationMesssanger Icon = "ApplicationMesssanger"
IconApplicationPhone Icon = "ApplicationPhone"
IconApplicationMail Icon = "ApplicationMail"
IconApplicationTerminalEmulator Icon = "ApplicationTerminalEmulator"
IconApplicationFileBrowser Icon = "ApplicationFileBrowser"
IconApplicationTextEditor Icon = "ApplicationTextEditor"
IconApplicationDocumentViewer Icon = "ApplicationDocumentViewer"
IconApplicationWordProcessor Icon = "ApplicationWordProcessor"
IconApplicationSpreadsheet Icon = "ApplicationSpreadsheet"
IconApplicationSlideshow Icon = "ApplicationSlideshow"
IconApplicationCalculator Icon = "ApplicationCalculator"
IconApplicationPreferences Icon = "ApplicationPreferences"
IconApplicationProcessManager Icon = "ApplicationProcessManager"
IconApplicationSystemInformation Icon = "ApplicationSystemInformation"
IconApplicationManual Icon = "ApplicationManual"
IconApplicationCamera Icon = "ApplicationCamera"
IconApplicationImageViewer Icon = "ApplicationImageViewer"
IconApplicationMediaPlayer Icon = "ApplicationMediaPlayer"
IconApplicationImageEditor Icon = "ApplicationImageEditor"
IconApplicationAudioEditor Icon = "ApplicationAudioEditor"
IconApplicationVideoEditor Icon = "ApplicationVideoEditor"
IconApplicationClock Icon = "ApplicationClock"
IconApplicationCalendar Icon = "ApplicationCalendar"
IconApplicationChecklist Icon = "ApplicationChecklist"
// objects: networks
IconNetwork Icon = "Network" // generic
IconNetworkLocal Icon = "NetworkLocal"
IconNetworkInternet Icon = "NetworkInternet"
IconNetworkEthernet Icon = "NetworkEthernet"
IconNetworkWireless Icon = "NetworkWireless"
IconNetworkCell Icon = "NetworkCell"
IconNetworkBluetooth Icon = "NetworkBluetooth"
IconNetworkRadio Icon = "NetworkRadio"
// objects: devices
IconDevice Icon = "Device" // generic
IconDeviceRouter Icon = "DeviceRouter"
IconDeviceServer Icon = "DeviceServer"
IconDeviceDesktop Icon = "DeviceDesktop"
IconDeviceLaptop Icon = "DeviceLaptop"
IconDeviceTablet Icon = "DeviceTablet"
IconDevicePhone Icon = "DevicePhone"
IconDeviceWatch Icon = "DeviceWatch"
IconDeviceCamera Icon = "DeviceCamera"
// objects: peripherals
IconPeripheral Icon = "Peripheral" // generic
IconPeripheralKeyboard Icon = "PeripheralKeyboard"
IconPeripheralMouse Icon = "PeripheralMouse"
IconPeripheralMonitor Icon = "PeripheralMonitor"
IconPeripheralWebcam Icon = "PeripheralWebcam"
IconPeripheralMicrophone Icon = "PeripheralMicrophone"
IconPeripheralSpeaker Icon = "PeripheralSpeaker"
IconPeripheralPenTablet Icon = "PeripheralPenTablet"
IconPeripheralTrackpad Icon = "PeripheralTrackpad"
IconPeripheralController Icon = "PeripheralController"
// objects: i/o
IconPort Icon = "Port" // generic
IconPortEthernet Icon = "PortEthernet"
IconPortUSB Icon = "PortUSB"
IconPortParallel Icon = "PortParallel"
IconPortSerial Icon = "PortSerial"
IconPortPS2 Icon = "PortPS2"
IconPortDisplay Icon = "PortDisplay"
IconPortCGA Icon = "PortCGA"
IconPortVGA Icon = "PortVGA"
IconPortHDMI Icon = "PortHDMI"
IconPortDisplayPort Icon = "PortDisplayPort"
IconPortInfrared Icon = "PortInfrared"
// actions: files
IconActionOpen Icon = "ActionOpen"
IconActionOpenIn Icon = "ActionOpenIn"
IconActionSave Icon = "ActionSave"
IconActionSaveAs Icon = "ActionSaveAs"
IconActionPrint Icon = "ActionPrint"
IconActionNew Icon = "ActionNew"
IconActionNewDirectory Icon = "ActionNewDirectory"
IconActionDelete Icon = "ActionDelete"
IconActionRename Icon = "ActionRename"
IconActionGetInformation Icon = "ActionGetInformation"
IconActionChangePermissions Icon = "ActionChangePermissions"
IconActionRevert Icon = "ActionRevert"
// actions: list management
IconActionAdd Icon = "ActionAdd"
IconActionRemove Icon = "ActionRemove"
IconActionAddBookmark Icon = "ActionAddBookmark"
IconActionRemoveBookmark Icon = "ActionRemoveBookmark"
IconActionAddFavorite Icon = "ActionAddFavorite"
IconActionRemoveFavorite Icon = "ActionRemoveFavorite"
// actions: media
IconActionPlay Icon = "ActionPlay"
IconActionPause Icon = "ActionPause"
IconActionStop Icon = "ActionStop"
IconActionFastForward Icon = "ActionFastForward"
IconActionRewind Icon = "ActionRewind"
IconActionToBeginning Icon = "ActionToBeginning"
IconActionToEnd Icon = "ActionToEnd"
IconActionRecord Icon = "ActionRecord"
IconActionVolumeUp Icon = "ActionVolumeUp"
IconActionVolumeDown Icon = "ActionVolumeDown"
IconActionMute Icon = "ActionMute"
// actions: editing
IconActionUndo Icon = "ActionUndo"
IconActionRedo Icon = "ActionRedo"
IconActionCut Icon = "ActionCut"
IconActionCopy Icon = "ActionCopy"
IconActionPaste Icon = "ActionPaste"
IconActionFind Icon = "ActionFind"
IconActionReplace Icon = "ActionReplace"
IconActionSelectAll Icon = "ActionSelectAll"
IconActionSelectNone Icon = "ActionSelectNone"
IconActionIncrement Icon = "ActionIncrement"
IconActionDecrement Icon = "ActionDecrement"
// actions: window management
IconActionClose Icon = "ActionClose"
IconActionQuit Icon = "ActionQuit"
IconActionIconify Icon = "ActionIconify"
IconActionShade Icon = "ActionShade"
IconActionMaximize Icon = "ActionMaximize"
IconActionFullScreen Icon = "ActionFullScreen"
IconActionRestore Icon = "ActionRestore"
// actions: view
IconActionExpand Icon = "ActionExpand"
IconActionContract Icon = "ActionContract"
IconActionBack Icon = "ActionBack"
IconActionForward Icon = "ActionForward"
IconActionUp Icon = "ActionUp"
IconActionDown Icon = "ActionDown"
IconActionReload Icon = "ActionReload"
IconActionZoomIn Icon = "ActionZoomIn"
IconActionZoomOut Icon = "ActionZoomOut"
IconActionZoomReset Icon = "ActionZoomReset"
IconActionMove Icon = "ActionMove"
IconActionResize Icon = "ActionResize"
IconActionGoTo Icon = "ActionGoTo"
// actions: tools
IconActionTransform Icon = "ActionTransform"
IconActionTranslate Icon = "ActionTranslate"
IconActionRotate Icon = "ActionRotate"
IconActionScale Icon = "ActionScale"
IconActionWarp Icon = "ActionWarp"
IconActionCornerPin Icon = "ActionCornerPin"
IconActionSelectRectangle Icon = "ActionSelectRectangle"
IconActionSelectEllipse Icon = "ActionSelectEllipse"
IconActionSelectLasso Icon = "ActionSelectLasso"
IconActionSelectGeometric Icon = "ActionSelectGeometric"
IconActionSelectAuto Icon = "ActionSelectAuto"
IconActionCrop Icon = "ActionCrop"
IconActionFill Icon = "ActionFill"
IconActionGradient Icon = "ActionGradient"
IconActionPencil Icon = "ActionPencil"
IconActionBrush Icon = "ActionBrush"
IconActionEraser Icon = "ActionEraser"
IconActionText Icon = "ActionText"
IconActionEyedropper Icon = "ActionEyedropper"
// status: dialog
IconStatusInformation Icon = "StatusInformation"
IconStatusQuestion Icon = "StatusQuestion"
IconStatusWarning Icon = "StatusWarning"
IconStatusError Icon = "StatusError"
IconStatusCancel Icon = "StatusCancel"
IconStatusOkay Icon = "StatusOkay"
// status: network
IconStatusCellSignal0 Icon = "StatusCellSignal0"
IconStatusCellSignal1 Icon = "StatusCellSignal1"
IconStatusCellSignal2 Icon = "StatusCellSignal2"
IconStatusCellSignal3 Icon = "StatusCellSignal3"
IconStatusWirelessSignal0 Icon = "StatusWirelessSignal0"
IconStatusWirelessSignal1 Icon = "StatusWirelessSignal1"
IconStatusWirelessSignal2 Icon = "StatusWirelessSignal2"
IconStatusWirelessSignal3 Icon = "StatusWirelessSignal3"
// status: power
IconStatusBattery0 Icon = "StatusBattery0"
IconStatusBattery1 Icon = "StatusBattery1"
IconStatusBattery2 Icon = "StatusBattery2"
IconStatusBattery3 Icon = "StatusBattery3"
IconStatusBrightness0 Icon = "StatusBrightness0"
IconStatusBrightness1 Icon = "StatusBrightness1"
IconStatusBrightness2 Icon = "StatusBrightness2"
IconStatusBrightness3 Icon = "StatusBrightness3"
// status: media
IconStatusVolume0 Icon = "StatusVolume0"
IconStatusVolume1 Icon = "StatusVolume1"
IconStatusVolume2 Icon = "StatusVolume2"
IconStatusVolume3 Icon = "StatusVolume3"
)
// Texture returns a texture of the corresponding icon ID.
func (id Icon) Texture (size IconSize) canvas.Texture {
if current == nil { return nil }
return current.Icon(id, size)
}
// MimeIcon returns an icon corresponding to a MIME type.
func MimeIcon (mime data.Mime, size IconSize) canvas.Texture {
if current == nil { return nil }
return current.MimeIcon(mime, size)
}

View File

@ -1,14 +1,17 @@
package theme
import "fmt"
import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/tomo/data"
import "git.tebibyte.media/tomo/tomo/event"
import "git.tebibyte.media/tomo/tomo/canvas"
// Role describes the role of an object.
type Role struct {
// Package is an optional namespace field. If specified, it should be
// the package name or module name the object is from.
Package string
// Object specifies what type of object it is. For example:
// - TextInput
// - Table
@ -16,12 +19,24 @@ type Role struct {
// - Dial
// This should correspond directly to the type name of the object.
Object string
// Variant is an optional field to be used when an object has one or
// more soft variants under one type. For example, an object "Slider"
// may have variations "horizontal" and "vertical".
Variant string
}
// String satisfies the fmt.Stringer interface.
// It follows the format of:
// Package.Object[Variant]
func (r Role) String () string {
return fmt.Sprintf("%s.%s[%s]", r.Package, r.Object, r.Variant)
}
// R is shorthand for creating a Role structure.
func R (pack, object string) Role {
return Role { Package: pack, Object: object }
}
func R (pack, object, variant string) Role {
return Role { Package: pack, Object: object, Variant: variant }
}
// Color represents a color ID.
type Color int; const (
@ -32,21 +47,50 @@ type Color int; const (
ColorAccent
)
// String satisfies the fmt.Stringer interface.
func (c Color) String () string {
switch c {
case ColorBackground: return "background"
case ColorForeground: return "foreground"
case ColorRaised: return "raised"
case ColorSunken: return "sunken"
case ColorAccent: return "accent"
default: return "unknown"
}
}
// RGBA satisfies the color.Color interface.
func (id Color) RGBA () (r, g, b, a uint32) {
if current == nil { return }
return current.RGBA(id)
}
// Theme is an object that can apply a visual style to different objects.
// Theme can apply a visual style to different objects.
type Theme interface {
// A word on textures:
//
// Because textures can be linked to some resource that is outside of
// the control of Go's garbage collector, methods of Theme must not
// allocate new copies of a texture each time they are called. It is
// fine to lazily load textures and save them for later use, but the
// same texture must never be allocated multiple times as this could
// cause a memory leak.
//
// As such, textures returned by these methods must be protected.
// Apply applies the theme to the given object, according to the given
// role. This may register event listeners with the given object;
// closing the returned cookie will remove them.
// closing the returned cookie must remove them.
Apply (tomo.Object, Role) event.Cookie
// RGBA returns the RGBA values of the corresponding color ID.
RGBA (Color) (r, g, b, a uint32)
// Icon returns a texture of the corresponding icon ID.
Icon (Icon, IconSize) canvas.Texture
// MimeIcon returns an icon corresponding to a MIME type.
MimeIcon (data.Mime, IconSize) canvas.Texture
}
var current Theme
@ -63,4 +107,3 @@ func Apply (object tomo.Object, role Role) event.Cookie {
if current == nil { return event.NoCookie { } }
return current.Apply(object, role)
}

18
tomo.go
View File

@ -3,6 +3,7 @@ package tomo
import "sync"
import "image"
import "errors"
import "git.tebibyte.media/tomo/tomo/canvas"
var backendLock sync.Mutex
var backend Backend
@ -11,8 +12,6 @@ var backend Backend
// event loop in that order. This function blocks until Stop is called, or the
// backend experiences a fatal error.
func Run (callback func ()) error {
loadPlugins()
if backend != nil {
return errors.New("there is already a backend running")
}
@ -56,6 +55,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()
@ -79,3 +86,10 @@ func NewContainerBox () ContainerBox {
assertBackend()
return backend.NewContainerBox()
}
// 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.TextureCloser {
assertBackend()
return backend.NewTexture(source)
}

22
unix.go
View File

@ -1,22 +0,0 @@
//go:build linux || darwin || freebsd
package tomo
import "os"
import "strings"
import "path/filepath"
func init () {
pathVariable := os.Getenv("TOMO_PLUGIN_PATH")
pluginPaths = strings.Split(pathVariable, ":")
pluginPaths = append (
pluginPaths,
"/usr/lib/tomo/plugins",
"/usr/local/lib/tomo/plugins")
homeDir, err := os.UserHomeDir()
if err == nil {
pluginPaths = append (
pluginPaths,
filepath.Join(homeDir, ".local/lib/tomo/plugins"))
}
}