377 lines
16 KiB
Go
377 lines
16 KiB
Go
package tomo
|
|
|
|
import "image"
|
|
import "git.tebibyte.media/tomo/tomo/text"
|
|
import "git.tebibyte.media/tomo/tomo/data"
|
|
import "git.tebibyte.media/tomo/tomo/event"
|
|
import "git.tebibyte.media/tomo/tomo/input"
|
|
import "git.tebibyte.media/tomo/tomo/canvas"
|
|
|
|
// Object is any onscreen object that is linked to a box (or is that box).
|
|
// Unlike the Box interface and associated interfaces, Object implementations
|
|
// may originate from anywhere.
|
|
type Object interface {
|
|
GetBox () Box
|
|
}
|
|
|
|
// ContentObject is an Object that contains some kind of content.
|
|
type ContentObject interface {
|
|
Object
|
|
|
|
// ContentBounds returns the bounds of the inner content of the Box
|
|
// 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.
|
|
ScrollTo (image.Point)
|
|
// OnContentBoundsChange specifies a function to be called when the
|
|
// Box's ContentBounds or InnerBounds changes.
|
|
OnContentBoundsChange (func ()) event.Cookie
|
|
}
|
|
|
|
// Box is a basic box with no content. Implementations of Box, as well as any
|
|
// interface that embed Box, may only originate from a Backend.
|
|
type Box interface {
|
|
Object
|
|
|
|
// Window returns the Window this Box is a part of.
|
|
Window () Window
|
|
// Bounds returns the outer bounding image.Rectangle of the Box relative
|
|
// to the Window.
|
|
Bounds () image.Rectangle
|
|
// InnerBounds returns the inner bounding image.Rectangle of the box. It
|
|
// is the value of Bounds inset by the Box's border and padding.
|
|
InnerBounds () image.Rectangle
|
|
// Role returns this Box's role as set by SetRole.
|
|
Role () Role
|
|
// SetRole sets what role this Box takes on. It is used by the Backend
|
|
// for applying styling.
|
|
SetRole (Role)
|
|
// Tag returns whether or not a named tag exists. These are used by the
|
|
// Backend for applying styling, among other things. There are some
|
|
// special tags that are only and always extant during certain user
|
|
// input states:
|
|
// - hovered: The mouse pointer is within the Box
|
|
// - focused: The Box has keyboard focus
|
|
// - pressed: The Box is being pressed by config.ButtonChordInteract
|
|
Tag (string) bool
|
|
// SetTag adds or removes a named tag.
|
|
SetTag (string, bool)
|
|
|
|
// SetAttr sets a style attribute, overriding the currently applied
|
|
// style.
|
|
SetAttr (Attr)
|
|
// UnsetAttr reverts a style attribute to whatever is specified by the
|
|
// currently applied style.
|
|
UnsetAttr (AttrKind)
|
|
|
|
// SetDNDData sets the data that will be picked up if this Box is
|
|
// dragged. If this is nil (which is the default), this Box will not be
|
|
// picked up.
|
|
SetDNDData (data.Data)
|
|
// SetDNDAccept sets the types of data which can be dropped onto this
|
|
// Box. If none are specified (which is the default), this Box will
|
|
// reject all drops.
|
|
SetDNDAccept (...data.Mime)
|
|
// SetFocused sets whether or not this Box has keyboard focus. If set to
|
|
// true, this method will steal focus away from whichever Object
|
|
// currently has focus.
|
|
SetFocused (bool)
|
|
// SetFocusable sets whether or not this Box can receive keyboard focus.
|
|
// If set to false and the Box is already focused. the focus is removed.
|
|
SetFocusable (bool)
|
|
|
|
// These are event subscription behaviors that allow callbacks to be
|
|
// connected to particular events. Multiple callbacks may be connected
|
|
// to the same event at once. Callbacks can be removed by closing the
|
|
// returned event.Cookie.
|
|
OnFocusEnter (func () ) event.Cookie
|
|
OnFocusLeave (func () ) event.Cookie
|
|
OnStyleChange (func () ) event.Cookie
|
|
OnIconSetChange (func () ) event.Cookie
|
|
OnDNDEnter (func () ) event.Cookie
|
|
OnDNDLeave (func () ) event.Cookie
|
|
OnDNDDrop (func (data.Data)) event.Cookie
|
|
OnMouseEnter (func () ) event.Cookie
|
|
OnMouseLeave (func () ) event.Cookie
|
|
// These event subscription behaviors require their callbacks to return
|
|
// a bool value. Under normal circumstances, these events are propagated
|
|
// to the Box which is most directly affected by them, and then to all
|
|
// of its parents from the bottom-up. Returning true from the callback
|
|
// will cause the propagation to stop immediately, thereby "catching"
|
|
// the event.
|
|
//
|
|
// Generally, if the event was successfully handled, the callbacks ought
|
|
// to return true. Additionally, when subscribing to an event that is
|
|
// often paired with a second one (for example, KeyDown and KeyUp), it
|
|
// is good practice to subscribe to both and return true/false under the
|
|
// same circumstances.
|
|
OnMouseMove (func () bool) event.Cookie
|
|
OnButtonDown (func (button input.Button) bool) event.Cookie
|
|
OnButtonUp (func (button input.Button) bool) event.Cookie
|
|
OnScroll (func (deltaX, deltaY float64) bool) event.Cookie
|
|
OnKeyDown (func (key input.Key, numberPad bool) bool) event.Cookie
|
|
OnKeyUp (func (key input.Key, numberPad bool) bool) event.Cookie
|
|
}
|
|
|
|
// CanvasBox is a Box that can be drawn to.
|
|
type CanvasBox interface {
|
|
Box
|
|
|
|
// SetDrawer sets the canvas.Drawer that will be called upon to draw the
|
|
// Box's content when it is invalidated. The Canvas passed to the Drawer
|
|
// will have these properties:
|
|
// - It will have the same origin (0, 0) as the Window which contains
|
|
// the CanvasBox.
|
|
// - Its Bounds will describe the portion of the CanvasBox visible on
|
|
// screen. Therefore, it should not be used to determine the
|
|
// position of anything drawn within it. The Bounds of the CanvasBox
|
|
// should be used for this purpose.
|
|
SetDrawer (canvas.Drawer)
|
|
|
|
// Invalidate causes the CanvasBox's area to be redrawn at the end of
|
|
// the event cycle, even if it wouldn't otherwise be. This will call the
|
|
// canvas.Drawer specified by SetDrawer.
|
|
Invalidate ()
|
|
}
|
|
|
|
// SurfaceBox is a Box that can be drawn to via a hardware accelerated (or
|
|
// platform-specific) graphics context.
|
|
type SurfaceBox interface {
|
|
Box
|
|
|
|
// Surface returns the underlying graphics context. The result must be
|
|
// asserted to the expected type or passed through a type switch before
|
|
// use. The exact type returned here depends on the Backend being used,
|
|
// and it is up to the application author to ensure that the application
|
|
// and Backend agree on it. Applications should fail gracefully if the
|
|
// expected type was not found. If the surface has been destroyed by the
|
|
// Backend, it will return nil.
|
|
Surface () any
|
|
|
|
// Invalidate causes the data within the surface to be pushed to the
|
|
// screen at the end of the event cycle, even if it wouldn't otherwise
|
|
// be.
|
|
Invalidate ()
|
|
|
|
// OnSizeChange specifies a function to be called when the size of the
|
|
// Box is changed, the surface is re-allocated, or the surface is
|
|
// destroyed. The application must call Surface() each time this event
|
|
// fires in order to not draw onto a closed surface.
|
|
OnSizeChange (func ())
|
|
}
|
|
|
|
// ContentBox is a box that has some kind of content.
|
|
type ContentBox interface {
|
|
Box
|
|
|
|
// ContentBounds returns the bounds of the inner content of the Box
|
|
// 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 image.Point.
|
|
ScrollTo (image.Point)
|
|
|
|
// OnContentBoundsChange specifies a function to be called when the
|
|
// Box's ContentBounds or InnerBounds changes.
|
|
OnContentBoundsChange (func ()) event.Cookie
|
|
}
|
|
|
|
// TextBox is a box that contains text content.
|
|
type TextBox interface {
|
|
ContentBox
|
|
|
|
// SetText sets the text content of the Box.
|
|
SetText (string)
|
|
|
|
// SetSelectable sets whether or not the text content can be
|
|
// highlighted/selected.
|
|
SetSelectable (bool)
|
|
// Select sets the text cursor or selection.
|
|
Select (text.Dot)
|
|
// Dot returns the text cursor or selection.
|
|
Dot () text.Dot
|
|
// OnDotChange specifies a function to be called when the text cursor or
|
|
// selection changes.
|
|
OnDotChange (func ()) event.Cookie
|
|
}
|
|
|
|
// ContentBox is a box that can contain child Objects. It arranges them
|
|
// according to a layout rule.
|
|
type ContainerBox interface {
|
|
ContentBox
|
|
|
|
// Add appends a child Object. If the Object is already a child of
|
|
// another Object, it will be removed from that Object first.
|
|
Add (Object)
|
|
// Remove removes a child Object, if it is a child of this Box.
|
|
Remove (Object)
|
|
// Insert inserts a child Object before a specified Object. If the
|
|
// before Object is nil or is not contained within this Box, the
|
|
// inserted Object is appended.
|
|
Insert (child Object, before Object)
|
|
// Clear removes all child Objects.
|
|
Clear ()
|
|
// Len returns the amount of child Objects.
|
|
Len () int
|
|
// At returns the child Object at the specified index.
|
|
At (int) Object
|
|
// SetInputMask sets whether or not user input events will be sent to
|
|
// this Box's children. If false, which is the default, input events
|
|
// will be sent to this Box as well as all of its children. If true,
|
|
// any input events that would otherwise go to this Box's children are
|
|
// sent to it instead. This prevents children from performing event
|
|
// catching as described in the documentation for Box.
|
|
SetInputMask (bool)
|
|
|
|
// TODO: if it turns out selecting specific kinds of events to mask off
|
|
// is a good idea, have SetInputMask take in a vararg list of event
|
|
// types.
|
|
}
|
|
|
|
// LayoutHints are passed to a layout to tell it how to arrange child Boxes.
|
|
type LayoutHints struct {
|
|
// Bounds is the bounding rectangle that children should be placed
|
|
// within. Any padding values are already applied.
|
|
Bounds image.Rectangle
|
|
// OverflowX and OverflowY control whether child Boxes may be positioned
|
|
// outside of Bounds.
|
|
OverflowX bool
|
|
OverflowY bool
|
|
// AlignX and AlignY control how child Boxes are aligned horizontally
|
|
// and vertically. The effect of this may vary depending on the Layout.
|
|
AlignX Align
|
|
AlignY Align
|
|
// Gap controls the amount of horizontal and vertical spacing in-between
|
|
// child Boxes.
|
|
Gap image.Point
|
|
}
|
|
|
|
// A Layout can be given to a ContainerBox to arrange child objects.
|
|
type Layout interface {
|
|
// MinimumSize returns the minimum width and height of
|
|
// LayoutHints.Bounds needed to properly lay out all child Boxes.
|
|
MinimumSize (LayoutHints, BoxQuerier) image.Point
|
|
// Arrange arranges child Boxes according to the given LayoutHints.
|
|
Arrange (LayoutHints, BoxArranger)
|
|
// RecommendedHeight returns the recommended height for a given width,
|
|
// if supported. Otherwise, it should just return the minimum height.
|
|
// The result of this behavior may or may not be respected, depending on
|
|
// the situation.
|
|
RecommendedHeight (LayoutHints, BoxQuerier, int) int
|
|
// RecommendedWidth returns the recommended width for a given height, if
|
|
// supported. Otherwise, it should just return the minimum width. The
|
|
// result of this behavior may or may not be respected, depending on the
|
|
// situation.
|
|
RecommendedWidth (LayoutHints, BoxQuerier, int) int
|
|
}
|
|
|
|
// BoxQuerier allows the attributes of a ContainerBox's children to be queried.
|
|
type BoxQuerier interface {
|
|
// Len returns the amount of Boxes.
|
|
Len () int
|
|
// MinimumSize returns the minimum size of a Box.
|
|
MinimumSize (index int) image.Point
|
|
// RecommendedWidth returns the recommended width for a given height for
|
|
// a Box, if supported. Otherwise, it should just return the minimum
|
|
// width of that Box. The result of this behavior may or may not be
|
|
// respected, depending on the situation.
|
|
RecommendedWidth (index int, height int) int
|
|
// RecommendedHeight returns the recommended height for a given width
|
|
// for a Box, if supported. Otherwise, it should just return the minimum
|
|
// width of that Box. The result of this behavior may or may not be
|
|
// respected, depending on the situation.
|
|
RecommendedHeight (index int, width int) int
|
|
}
|
|
|
|
// BoxArranger is a BoxQuerier that allows arranging child boxes according to a
|
|
// layout.
|
|
type BoxArranger interface {
|
|
BoxQuerier
|
|
|
|
// SetBounds sets the bounds of a Box.
|
|
SetBounds (index int, bounds image.Rectangle)
|
|
}
|
|
|
|
// WindowKind specifies a Window's kind, which determines how it is displayed
|
|
// and managed by the operating system.
|
|
type WindowKind string; const (
|
|
// Normal is a normal Window.
|
|
WindowKindNormal WindowKind = "Normal"
|
|
// Plain is an undecorated Window that does not appear in window lists.
|
|
// It is intended for things like docks, panels, etc.
|
|
WindowKindPlain WindowKind = "Plain"
|
|
// Utility is a small Window for toolboxes, command palletes, etc. It is
|
|
// usually given special styling and management by the OS.
|
|
WindowKindUtility WindowKind = "Utility"
|
|
// Turn is a small Window for menus and panes which have been "torn off"
|
|
// from their main Window or position. It is usually given special
|
|
// styling and management by the OS.
|
|
WindowKindTorn WindowKind = "Toolbar"
|
|
// Menu is an undecorated Window for drop down menus, context menus,
|
|
// etc. It closes once the user interacts outside of it.
|
|
WindowKindMenu WindowKind = "Menu"
|
|
// Modal, while open, blocks all user input from reaching its parent
|
|
// window, forcing the user's attention. It is usually given special
|
|
// styling and management by the OS. Note that in some environments it
|
|
// will not be given window controls, so it should contain some "Close"
|
|
// or "Cancel" button.
|
|
WindowKindModal WindowKind = "Modal"
|
|
)
|
|
|
|
// Window is an operating system Window. It can directly contain one object,
|
|
// which is usually a container. Windows themselves are completely transparent,
|
|
// and become opaque once an opaque object is added as their root.
|
|
type Window interface {
|
|
// Bounds returns the bounds of the Window including its frame, if
|
|
// possible. This means that the top-left point of the bounds will be
|
|
// either zero or negative.
|
|
Bounds () image.Rectangle
|
|
// InnerBounds returns the inner bounds of the Window, not including its
|
|
// frame. This means that the top-left point of the bounds will be zero.
|
|
InnerBounds () image.Rectangle
|
|
// SetRoot sets the root child of the Window. There can only be one at
|
|
// a time, and setting it will remove the current child if there is one.
|
|
SetRoot (Object)
|
|
// SetTitle sets the title of the Window.
|
|
SetTitle (string)
|
|
// SetIcon sets the icon of the Window.
|
|
SetIcon (Icon)
|
|
// SetResizable sets whether the Window can be resized by the user in
|
|
// the X and Y directions. If one or both axes are false, the ones that
|
|
// are will be shrunk to the Window's minimum size.
|
|
SetResizable (x, y bool)
|
|
// SetBounds sets this Window's bounds. This may or may not have any
|
|
// effect on the Window's position on screen depending on the platform.
|
|
SetBounds (image.Rectangle)
|
|
// NewChild creates a new Window that is semantically a child of this
|
|
// Window. It does not actually reside within this Window, but it may be
|
|
// linked to it via some other means.
|
|
NewChild (WindowKind, image.Rectangle) (Window, error)
|
|
// Modifiers returns which modifier keys on the keyboard are currently
|
|
// being held down.
|
|
Modifiers () input.Modifiers
|
|
// MousePosition returns the position of the mouse pointer relative to
|
|
// the Window.
|
|
MousePosition () image.Point
|
|
// Copy copies data to the clipboard.
|
|
Copy (data.Data)
|
|
// Paste reads data from the clipboard. When the data is available or an
|
|
// error has occurred, the provided function will be called.
|
|
Paste (callback func (data.Data, error), accept ...data.Mime)
|
|
// SetVisible sets whether or not this window is visible. Windows are
|
|
// invisible by default.
|
|
SetVisible (bool)
|
|
// Visible returns whether or not this window is visible.
|
|
Visible () bool
|
|
// Close closes the window. This does not trigger the TryClose event.
|
|
Close () error
|
|
// OnTryClose specifies a function to be called when the user attempts
|
|
// to close the Window. If any registered handlers returns false, the
|
|
// Window will not be closed. This can be used to display some sort of
|
|
// "Unsaved changes" warning to the user.
|
|
OnTryClose (func () bool) event.Cookie
|
|
// OnClose specifies a function to be called when the Window is closed.
|
|
OnClose (func ()) event.Cookie
|
|
}
|