From 4c9743387bbb29cc0b7cc553d9da7db840f3d44c Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Sat, 29 Apr 2023 14:23:21 -0400 Subject: [PATCH] Moved a lot of interfaces out of the base tomo module and into an abilities module --- ability/doc.go | 6 ++ ability/element.go | 241 +++++++++++++++++++++++++++++++++++++++++++++ ability/entity.go | 101 +++++++++++++++++++ element.go | 240 +------------------------------------------- entity.go | 101 +------------------ 5 files changed, 352 insertions(+), 337 deletions(-) create mode 100644 ability/doc.go create mode 100644 ability/element.go create mode 100644 ability/entity.go diff --git a/ability/doc.go b/ability/doc.go new file mode 100644 index 0000000..e526351 --- /dev/null +++ b/ability/doc.go @@ -0,0 +1,6 @@ +// Package ability defines extended interfaces that elements and entities can +// support. +// +// Note that backends must give an entity that satisfies the corresponding +// entity interface to an element satisfying a given element interface. +package ability diff --git a/ability/element.go b/ability/element.go new file mode 100644 index 0000000..416bde9 --- /dev/null +++ b/ability/element.go @@ -0,0 +1,241 @@ +package ability + +import "image" +import "git.tebibyte.media/sashakoshka/tomo" +import "git.tebibyte.media/sashakoshka/tomo/input" +import "git.tebibyte.media/sashakoshka/tomo/canvas" + +// Layoutable represents an element that needs to perform layout calculations +// before it can draw itself. +type Layoutable interface { + tomo.Element + + // Layout causes this element to perform a layout operation. + Layout () +} + +// Container represents an element capable of containing child elements. +type Container interface { + tomo.Element + Layoutable + + // DrawBackground causes the element to draw its background pattern to + // the specified canvas. The bounds of this canvas specify the area that + // is actually drawn to, while the Entity bounds specify the actual area + // of the element. + DrawBackground (canvas.Canvas) + + // HandleChildMinimumSizeChange is called when a child's minimum size is + // changed. + HandleChildMinimumSizeChange (child tomo.Element) +} + +// Enableable represents an element that can be enabled and disabled. Disabled +// elements typically appear greyed out. +type Enableable interface { + tomo.Element + + // Enabled returns whether or not the element is enabled. + Enabled () bool + + // SetEnabled sets whether or not the element is enabled. + SetEnabled (bool) +} + +// Focusable represents an element that has keyboard navigation support. +type Focusable interface { + tomo.Element + Enableable + + // HandleFocusChange is called when the element is focused or unfocused. + HandleFocusChange () +} + +// Selectable represents an element that can be selected. This includes things +// like list items, files, etc. The difference between this and Focusable is +// that multiple Selectable elements may be selected at the same time, whereas +// only one Focusable element may be focused at the same time. Containers who's +// purpose is to contain selectable elements can determine when to select them +// by implementing MouseTargetContainer and listening for HandleChildMouseDown +// events. +type Selectable interface { + tomo.Element + Enableable + + // HandleSelectionChange is called when the element is selected or + // deselected. + HandleSelectionChange () +} + +// KeyboardTarget represents an element that can receive keyboard input. +type KeyboardTarget interface { + tomo.Element + + // HandleKeyDown is called when a key is pressed down or repeated while + // this element has keyboard focus. It is important to note that not + // every key down event is guaranteed to be paired with exactly one key + // up event. This is the reason a list of modifier keys held down at the + // time of the key press is given. + HandleKeyDown (key input.Key, modifiers input.Modifiers) + + // HandleKeyUp is called when a key is released while this element has + // keyboard focus. + HandleKeyUp (key input.Key, modifiers input.Modifiers) +} + +// MouseTarget represents an element that can receive mouse events. +type MouseTarget interface { + tomo.Element + + // HandleMouseDown is called when a mouse button is pressed down on this + // element. + HandleMouseDown ( + position image.Point, + button input.Button, + modifiers input.Modifiers) + + // HandleMouseUp is called when a mouse button is released that was + // originally pressed down on this element. + HandleMouseUp ( + position image.Point, + button input.Button, + modifiers input.Modifiers) +} + +// MouseTargetContainer represents an element that wants to know when one +// of its children is clicked. Children do not have to implement MouseTarget for +// a container satisfying MouseTargetContainer to be notified that they have +// been clicked. +type MouseTargetContainer interface { + Container + + // HandleMouseDown is called when a mouse button is pressed down on a + // child element. + HandleChildMouseDown ( + position image.Point, + button input.Button, + modifiers input.Modifiers, + child tomo.Element) + + // HandleMouseUp is called when a mouse button is released that was + // originally pressed down on a child element. + HandleChildMouseUp ( + position image.Point, + button input.Button, + modifiers input.Modifiers, + child tomo.Element) +} + +// MotionTarget represents an element that can receive mouse motion events. +type MotionTarget interface { + tomo.Element + + // HandleMotion is called when the mouse is moved over this element, + // or the mouse is moving while being held down and originally pressed + // down on this element. + HandleMotion (position image.Point) +} + +// ScrollTarget represents an element that can receive mouse scroll events. +type ScrollTarget interface { + tomo.Element + + // HandleScroll is called when the mouse is scrolled. The X and Y + // direction of the scroll event are passed as deltaX and deltaY. + HandleScroll ( + position image.Point, + deltaX, deltaY float64, + modifiers input.Modifiers) +} + +// Flexible represents an element who's preferred minimum height can change in +// response to its width. +type Flexible interface { + tomo.Element + + // FlexibleHeightFor returns what the element's minimum height would be + // if resized to a specified width. This does not actually alter the + // state of the element in any way, but it may perform significant work, + // so it should be called sparingly. + // + // It is reccomended that parent containers check for this interface and + // take this method's value into account in order to support things like + // flow layouts and text wrapping, but it is not absolutely necessary. + // The element's MinimumSize method will still return the absolute + // minimum size that the element may be resized to. + // + // It is important to note that if a parent container checks for + // flexible chilren, it itself will likely need to be either scrollable + // or flexible. + FlexibleHeightFor (width int) int +} + +// FlexibleContainer represents an element that is capable of containing +// flexible children. +type FlexibleContainer interface { + Container + + // HandleChildFlexibleHeightChange is called when the parameters + // affecting a child's flexible height are changed. + HandleChildFlexibleHeightChange (child Flexible) +} + +// Scrollable represents an element that can be scrolled. It acts as a viewport +// through which its contents can be observed. +type Scrollable interface { + tomo.Element + + // ScrollContentBounds returns the full content size of the element. + ScrollContentBounds () image.Rectangle + + // ScrollViewportBounds returns the size and position of the element's + // viewport relative to ScrollBounds. + ScrollViewportBounds () image.Rectangle + + // ScrollTo scrolls the viewport to the specified point relative to + // ScrollBounds. + ScrollTo (position image.Point) + + // ScrollAxes returns the supported axes for scrolling. + ScrollAxes () (horizontal, vertical bool) +} + +// ScrollableContainer represents an element that is capable of containing +// scrollable children. +type ScrollableContainer interface { + Container + + // HandleChildScrollBoundsChange is called when the content bounds, + // viewport bounds, or scroll axes of a child are changed. + HandleChildScrollBoundsChange (child Scrollable) +} + +// Collapsible represents an element who's minimum width and height can be +// manually resized. Scrollable elements should implement this if possible. +type Collapsible interface { + tomo.Element + + // Collapse collapses the element's minimum width and height. A value of + // zero for either means that the element's normal value is used. + Collapse (width, height int) +} + +// Themeable represents an element that can modify its appearance to fit within +// a theme. +type Themeable interface { + tomo.Element + + // SetTheme sets the element's theme to something fulfilling the + // theme.Theme interface. + SetTheme (tomo.Theme) +} + +// Configurable represents an element that can modify its behavior to fit within +// a set of configuration parameters. +type Configurable interface { + tomo.Element + + // SetConfig sets the element's configuration to something fulfilling + // the config.Config interface. + SetConfig (tomo.Config) +} diff --git a/ability/entity.go b/ability/entity.go new file mode 100644 index 0000000..4f351dd --- /dev/null +++ b/ability/entity.go @@ -0,0 +1,101 @@ +package ability + +import "image" +import "git.tebibyte.media/sashakoshka/tomo" + +// LayoutEntity is given to elements that support the Layoutable interface. +type LayoutEntity interface { + tomo.Entity + + // InvalidateLayout marks the element's layout as invalid. At the end of + // every event, the backend will ask all invalid elements to recalculate + // their layouts. + InvalidateLayout () +} + +// ContainerEntity is given to elements that support the Container interface. +type ContainerEntity interface { + tomo.Entity + LayoutEntity + + // Adopt adds an element as a child. + Adopt (child tomo.Element) + + // Insert inserts an element in the child list at the specified + // location. + Insert (index int, child tomo.Element) + + // Disown removes the child at the specified index. + Disown (index int) + + // IndexOf returns the index of the specified child. + IndexOf (child tomo.Element) int + + // Child returns the child at the specified index. + Child (index int) tomo.Element + + // CountChildren returns the amount of children the element has. + CountChildren () int + + // PlaceChild sets the size and position of the child at the specified + // index to a bounding rectangle. + PlaceChild (index int, bounds image.Rectangle) + + // SelectChild marks a child as selected or unselected, if it is + // selectable. + SelectChild (index int, selected bool) + + // ChildMinimumSize returns the minimum size of the child at the + // specified index. + ChildMinimumSize (index int) (width, height int) +} + +// FocusableEntity is given to elements that support the Focusable interface. +type FocusableEntity interface { + tomo.Entity + + // Focused returns whether the element currently has input focus. + Focused () bool + + // Focus sets this element as focused. If this succeeds, the element will + // recieve a HandleFocus call. + Focus () + + // FocusNext causes the focus to move to the next element. If this + // succeeds, the element will recieve a HandleUnfocus call. + FocusNext () + + // FocusPrevious causes the focus to move to the next element. If this + // succeeds, the element will recieve a HandleUnfocus call. + FocusPrevious () +} + +// SelectableEntity is given to elements that support the Selectable interface. +type SelectableEntity interface { + tomo.Entity + + // Selected returns whether this element is currently selected. + Selected () bool +} + +// FlexibleEntity is given to elements that support the Flexible interface. +type FlexibleEntity interface { + tomo.Entity + + // NotifyFlexibleHeightChange notifies the system that the parameters + // affecting the element's flexible height have changed. This method is + // expected to be called by flexible elements when their content changes. + NotifyFlexibleHeightChange () +} + +// ScrollableEntity is given to elements that support the Scrollable interface. +type ScrollableEntity interface { + tomo.Entity + + // NotifyScrollBoundsChange notifies the system that the element's + // scroll content bounds or viewport bounds have changed. This is + // expected to be called by scrollable elements when they change their + // supported scroll axes, their scroll position (either autonomously or + // as a result of a call to ScrollTo()), or their content size. + NotifyScrollBoundsChange () +} diff --git a/element.go b/element.go index a92a4f7..1ade44c 100644 --- a/element.go +++ b/element.go @@ -1,10 +1,9 @@ package tomo -import "image" -import "git.tebibyte.media/sashakoshka/tomo/input" import "git.tebibyte.media/sashakoshka/tomo/canvas" -// Element represents a basic on-screen object. +// Element represents a basic on-screen object. Extended element interfaces are +// defined in the ability module. type Element interface { // Draw causes the element to draw to the specified canvas. The bounds // of this canvas specify the area that is actually drawn to, while the @@ -14,238 +13,3 @@ type Element interface { // Entity returns this element's entity. Entity () Entity } - -// Layoutable represents an element that needs to perform layout calculations -// before it can draw itself. -type Layoutable interface { - Element - - // Layout causes this element to perform a layout operation. - Layout () -} - -// Container represents an element capable of containing child elements. -type Container interface { - Element - Layoutable - - // DrawBackground causes the element to draw its background pattern to - // the specified canvas. The bounds of this canvas specify the area that - // is actually drawn to, while the Entity bounds specify the actual area - // of the element. - DrawBackground (canvas.Canvas) - - // HandleChildMinimumSizeChange is called when a child's minimum size is - // changed. - HandleChildMinimumSizeChange (child Element) -} - -// Enableable represents an element that can be enabled and disabled. Disabled -// elements typically appear greyed out. -type Enableable interface { - Element - - // Enabled returns whether or not the element is enabled. - Enabled () bool - - // SetEnabled sets whether or not the element is enabled. - SetEnabled (bool) -} - -// Focusable represents an element that has keyboard navigation support. -type Focusable interface { - Element - Enableable - - // HandleFocusChange is called when the element is focused or unfocused. - HandleFocusChange () -} - -// Selectable represents an element that can be selected. This includes things -// like list items, files, etc. The difference between this and Focusable is -// that multiple Selectable elements may be selected at the same time, whereas -// only one Focusable element may be focused at the same time. Containers who's -// purpose is to contain selectable elements can determine when to select them -// by implementing MouseTargetContainer and listening for HandleChildMouseDown -// events. -type Selectable interface { - Element - Enableable - - // HandleSelectionChange is called when the element is selected or - // deselected. - HandleSelectionChange () -} - -// KeyboardTarget represents an element that can receive keyboard input. -type KeyboardTarget interface { - Element - - // HandleKeyDown is called when a key is pressed down or repeated while - // this element has keyboard focus. It is important to note that not - // every key down event is guaranteed to be paired with exactly one key - // up event. This is the reason a list of modifier keys held down at the - // time of the key press is given. - HandleKeyDown (key input.Key, modifiers input.Modifiers) - - // HandleKeyUp is called when a key is released while this element has - // keyboard focus. - HandleKeyUp (key input.Key, modifiers input.Modifiers) -} - -// MouseTarget represents an element that can receive mouse events. -type MouseTarget interface { - Element - - // HandleMouseDown is called when a mouse button is pressed down on this - // element. - HandleMouseDown ( - position image.Point, - button input.Button, - modifiers input.Modifiers) - - // HandleMouseUp is called when a mouse button is released that was - // originally pressed down on this element. - HandleMouseUp ( - position image.Point, - button input.Button, - modifiers input.Modifiers) -} - -// MouseTargetContainer represents an element that wants to know when one -// of its children is clicked. Children do not have to implement MouseTarget for -// a container satisfying MouseTargetContainer to be notified that they have -// been clicked. -type MouseTargetContainer interface { - Container - - // HandleMouseDown is called when a mouse button is pressed down on a - // child element. - HandleChildMouseDown ( - position image.Point, - button input.Button, - modifiers input.Modifiers, - child Element) - - // HandleMouseUp is called when a mouse button is released that was - // originally pressed down on a child element. - HandleChildMouseUp ( - position image.Point, - button input.Button, - modifiers input.Modifiers, - child Element) -} - -// MotionTarget represents an element that can receive mouse motion events. -type MotionTarget interface { - Element - - // HandleMotion is called when the mouse is moved over this element, - // or the mouse is moving while being held down and originally pressed - // down on this element. - HandleMotion (position image.Point) -} - -// ScrollTarget represents an element that can receive mouse scroll events. -type ScrollTarget interface { - Element - - // HandleScroll is called when the mouse is scrolled. The X and Y - // direction of the scroll event are passed as deltaX and deltaY. - HandleScroll ( - position image.Point, - deltaX, deltaY float64, - modifiers input.Modifiers) -} - -// Flexible represents an element who's preferred minimum height can change in -// response to its width. -type Flexible interface { - Element - - // FlexibleHeightFor returns what the element's minimum height would be - // if resized to a specified width. This does not actually alter the - // state of the element in any way, but it may perform significant work, - // so it should be called sparingly. - // - // It is reccomended that parent containers check for this interface and - // take this method's value into account in order to support things like - // flow layouts and text wrapping, but it is not absolutely necessary. - // The element's MinimumSize method will still return the absolute - // minimum size that the element may be resized to. - // - // It is important to note that if a parent container checks for - // flexible chilren, it itself will likely need to be either scrollable - // or flexible. - FlexibleHeightFor (width int) int -} - -// FlexibleContainer represents an element that is capable of containing -// flexible children. -type FlexibleContainer interface { - Container - - // HandleChildFlexibleHeightChange is called when the parameters - // affecting a child's flexible height are changed. - HandleChildFlexibleHeightChange (child Flexible) -} - -// Scrollable represents an element that can be scrolled. It acts as a viewport -// through which its contents can be observed. -type Scrollable interface { - Element - - // ScrollContentBounds returns the full content size of the element. - ScrollContentBounds () image.Rectangle - - // ScrollViewportBounds returns the size and position of the element's - // viewport relative to ScrollBounds. - ScrollViewportBounds () image.Rectangle - - // ScrollTo scrolls the viewport to the specified point relative to - // ScrollBounds. - ScrollTo (position image.Point) - - // ScrollAxes returns the supported axes for scrolling. - ScrollAxes () (horizontal, vertical bool) -} - -// ScrollableContainer represents an element that is capable of containing -// scrollable children. -type ScrollableContainer interface { - Container - - // HandleChildScrollBoundsChange is called when the content bounds, - // viewport bounds, or scroll axes of a child are changed. - HandleChildScrollBoundsChange (child Scrollable) -} - -// Collapsible represents an element who's minimum width and height can be -// manually resized. Scrollable elements should implement this if possible. -type Collapsible interface { - Element - - // Collapse collapses the element's minimum width and height. A value of - // zero for either means that the element's normal value is used. - Collapse (width, height int) -} - -// Themeable represents an element that can modify its appearance to fit within -// a theme. -type Themeable interface { - Element - - // SetTheme sets the element's theme to something fulfilling the - // theme.Theme interface. - SetTheme (Theme) -} - -// Configurable represents an element that can modify its behavior to fit within -// a set of configuration parameters. -type Configurable interface { - Element - - // SetConfig sets the element's configuration to something fulfilling - // the config.Config interface. - SetConfig (Config) -} diff --git a/entity.go b/entity.go index bdeb562..48b30e3 100644 --- a/entity.go +++ b/entity.go @@ -3,8 +3,8 @@ package tomo import "image" import "git.tebibyte.media/sashakoshka/tomo/canvas" -// Entity is a handle given to elements by the backend. Different types of -// entities may be assigned to elements that support different capabilities. +// Entity is a handle given to elements by the backend. Extended entity +// interfaces are defined in the ability module. type Entity interface { // Invalidate marks the element's current visual as invalid. At the end // of every event, the backend will ask all invalid entities to redraw @@ -30,100 +30,3 @@ type Entity interface { // background pattern. DrawBackground (canvas.Canvas) } - -// LayoutEntity is given to elements that support the Layoutable interface. -type LayoutEntity interface { - Entity - - // InvalidateLayout marks the element's layout as invalid. At the end of - // every event, the backend will ask all invalid elements to recalculate - // their layouts. - InvalidateLayout () -} - -// ContainerEntity is given to elements that support the Container interface. -type ContainerEntity interface { - Entity - LayoutEntity - - // Adopt adds an element as a child. - Adopt (child Element) - - // Insert inserts an element in the child list at the specified - // location. - Insert (index int, child Element) - - // Disown removes the child at the specified index. - Disown (index int) - - // IndexOf returns the index of the specified child. - IndexOf (child Element) int - - // Child returns the child at the specified index. - Child (index int) Element - - // CountChildren returns the amount of children the element has. - CountChildren () int - - // PlaceChild sets the size and position of the child at the specified - // index to a bounding rectangle. - PlaceChild (index int, bounds image.Rectangle) - - // SelectChild marks a child as selected or unselected, if it is - // selectable. - SelectChild (index int, selected bool) - - // ChildMinimumSize returns the minimum size of the child at the - // specified index. - ChildMinimumSize (index int) (width, height int) -} - -// FocusableEntity is given to elements that support the Focusable interface. -type FocusableEntity interface { - Entity - - // Focused returns whether the element currently has input focus. - Focused () bool - - // Focus sets this element as focused. If this succeeds, the element will - // recieve a HandleFocus call. - Focus () - - // FocusNext causes the focus to move to the next element. If this - // succeeds, the element will recieve a HandleUnfocus call. - FocusNext () - - // FocusPrevious causes the focus to move to the next element. If this - // succeeds, the element will recieve a HandleUnfocus call. - FocusPrevious () -} - -// SelectableEntity is given to elements that support the Selectable interface. -type SelectableEntity interface { - Entity - - // Selected returns whether this element is currently selected. - Selected () bool -} - -// FlexibleEntity is given to elements that support the Flexible interface. -type FlexibleEntity interface { - Entity - - // NotifyFlexibleHeightChange notifies the system that the parameters - // affecting the element's flexible height have changed. This method is - // expected to be called by flexible elements when their content changes. - NotifyFlexibleHeightChange () -} - -// ScrollableEntity is given to elements that support the Scrollable interface. -type ScrollableEntity interface { - Entity - - // NotifyScrollBoundsChange notifies the system that the element's - // scroll content bounds or viewport bounds have changed. This is - // expected to be called by scrollable elements when they change their - // supported scroll axes, their scroll position (either autonomously or - // as a result of a call to ScrollTo()), or their content size. - NotifyScrollBoundsChange () -}