367 lines
15 KiB
Go
367 lines
15 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 has 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 styled box. 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 rectangle of the Box relative to
|
|
// the Window.
|
|
Bounds () image.Rectangle
|
|
// InnerBounds returns the inner bounding 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 to apply styling
|
|
// from a theme.
|
|
SetRole (Role)
|
|
// Tag returns whether or not a named tag exists. These are used 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 the left mouse button
|
|
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 type of data that can be dropped onto this Box.
|
|
// If this is nil (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 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.
|
|
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 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
|
|
// - The Canvas bounds will describe the portion of the CanvasBox
|
|
// visible on screen
|
|
SetDrawer (canvas.Drawer)
|
|
|
|
// Invalidate causes the Box's area to be redrawn at the end of the
|
|
// event cycle, even if it wouldn't be otherwise.
|
|
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.
|
|
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 be
|
|
// otherwise.
|
|
Invalidate ()
|
|
|
|
// OnSizeChange specifies a function to be called when the size of the
|
|
// Box is changed, or the surface is re-allocated. The application must
|
|
// call Surface() each time this event fires in order to not draw to 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 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 behavireor 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"
|
|
// Toolbar is a small window for menus and window panes which have been
|
|
// "torn off" from their main window or position. It is usually given
|
|
// special styling and management by the OS.
|
|
WindowKindToolbar 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 contain one object. 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
|
|
}
|