tomo/object.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
}