Agressive changes have been made to how updates are made to reduce the necessary fequency of calculations:
Rasterizer
has been merged intoDrawingGroup
.DrawingGroup
now uses draw lists by default. See documentation for how to disable this, for cases where it harms performance.Position
can now be expected to be called more than once for someLayout
calls, where sizing hasn't changed but positioning has (e.g. )- Even if rasterization isn't involved,
Draw
can be called more than once perPosition
/Layout
call. - To specifically request an update to any of
Layout
/Position
/Draw
, the corresponding property may be set on the relevantDrawingGroup
. SeeDrawer
andComponent
for more detail and example implementations.
To facilitate this:
- Most components that allow specifying a child no longer make their child editable; instead, when you wish to mutate a child view hierarchy, set the parent's initial child to
Box
, which allows its child to be changed (viaBox:SetChild(newChild)
). Rect
,MarginAroundRect
, andCell
no longer draw decorations. UseBackground
instead to attach a background. (Note thatBackground
doesn't have the rasterizing optimisation thatMarginAroundRect
did; instead, use nestedDrawingGroup
s to separate the re-drawing profile of different parts of the interface hierarchy.)HorizontalStack
,VerticalStack
, andStackInPlace
no longer make their members public; instead, they must be set/get through methods that copy to/from the internal member array.- Other mutable properties for other component types must be changed through methods, similar to above.
- Some properties are simply no longer mutable.
Dimension
now has a base constructor that registers for updates with the drawing group; the previous functionality of theDimension
function has moved toAutoScalingDimension
.OffsettedViewport
is now an overriding extension ofDrawingGroup
.
Changes to Menu
:
MenuAnchor
now providesmenuAnchor:GetMenu()
to allow accessing its menu.Menu
providesmenu:IsMouseOver()
which returns whether the user's cursor is over the menu or one of its submenus.Menu
's submenu menu items are now aMenuAnchor
at the top level, rather than aMarginAroundRect
at the top level. (This probably shouldn't be of practical concern to users of the framework.)
Misc other changes:
- Remove elements with incomplete
PrimaryFrame
geometry, to prevent log spam and allow interaction - Various bugfixes
- TextEntry & Button store their colours in constants, providing potential to override & set custom styles
PrimaryFrame
no longer attempts recovery ifLayout
hasn't been called yetElement
s are removed if noPrimaryFrame
is present in the view hierarchyHorizontalScrollContainer
andVerticalScrollContainer
now use the customisableframework.dimension.scrollMultiplier
to configure their scroll speed. This should provide the same scrolling experience on a 1080p display, and scale better to larger resolutions.
Extensions are now declared in MasterFramework $VERSION/Utils
, and pre-loaded before the rest of the framework. These are provided the same global environment as the rest of the framework. string
extensions now all have _MasterFramework
at the end of their name, while the table
extension overrides the Include.table
table for the framework, and provides access to the customised version as framework.table
. The definition of Include.clear
has been moved to Utils/table.lua
, and table.joinStrings()
has been removed, since it was a slower reimplementation of table.concat()
Constants have been moved out of gui_master_framework.lua
into separate files in the Constants/
directory. Subfiles are not automatically loaded to allow for dependencies, other than the entry point Constants/constants.lua
.
The main framework files which would have been loaded in previous versions are now contained in the Framework/
directory.
The new major directories are loaded in this order: Utils/
, Framework/
, then Constants/
.
Framework access is no longer provided as WG.MasterFramework[compatabilityVersion], instead as WG["MasterFramework " .. compatabilityVersion]. Removing the intermediate table technically simplifies this?
To make handling selection changes more graceful:
- Added
entry:CurrentCursorIndex()
returns the current primary selection index - i.e. which one should be manipulated on a selection change (based on selectFrom). - Added
entry:MoveCursor(destinationIndex, isShift)
to handle all keyboard-based selection changes.
All selection handling now uses entry:MoveCursor()
to ensure that selectFrom
, selectionChangedClock
, and entry.selectionEnd
are correctly updated. This also fixes some bugs with mouse selection where keyboard selection changes would be incorrect directly after a mouse selection.
Adds entry:editAbove()
and entry:editBelow()
for moving cursor up/down. Use with ctrl to jump to the next raw (not visual) newline.
TODO: entry:editAbove()
and entry:editBelow()
could remember the starting X coordinate, so as to not forget e.g. across a newline.
Simply implements the (ctrl) argument of textEntry:editDelete(ctrl)
, textEntry:editBackspace(ctrl)
, textEntry:editLeft(ctrl)
, textEntry:editRight(ctrl)
- rename
string:lines
tostring:lines_MasterFramework
to disambiguate from BAR's implementation - by default, don't extract a substring for each parsed line. Call
string:lines_MasterFramework(true)
to return an array of strings containing each extracted line.
WrappingText and TextEntry use this optimised lines function for better performance.
-
localize a few functions for speed
-
provided arguments for supplying a partial result to
wrappingText:RawIndexToDisplayIndex
to avoid repeated work -
other minor tweak(s)
-
Also slightly improves selection box drawing, namely including an indication of whether the newline is selected
Adds the following methods:
textEntry:InsertUndoAction(undoAction, redoAction)
: Adds an undo action and an associated redo action to the undo/redo log.textEntry:InsertText(newText)
: Inserts the text at the current index. The insertin is added to the undo/redo log.textEntry:editCopy()
: For a point selection, noop. For a block selection, copies the current selection to clipboard. (Called for a Ctrl+C keypress.)textEntry:editPaste()
: For a point selection, inserts the contents of the pasteboard at the current selection. For a block selection, copies the current selection to clipboard. (Called for a Ctrl+V keypress.) The text addition is added to the undo/redo log.textEntry:editCut()
: For a point selection, noop. For a block selection, copies the current selection to clipboard, and removes it from the textEntry's text. (Called for a Ctrl+C keypress.) The text removal is added to the undo/redo log.textEntry:editUndo()
: Applies any undo action at the current index, and increases the index by one. (Called for a Ctrl+Z keypress.)textEntry:editRedo()
: Applies any redo action at the current index, and decreases the index by one. (Called for a Ctrl+Shift+Z keypress.)
Editing clips the undo/redo log to the current index. Redo indices are offset by undo indices by one, such that a redo cannot be called until an undo has been performed, and once all undos have been performed, the last redo will still be available.
Specify true
for allowInteractionBehind
when calling framework:InsertElement()
to allow click-through
API changes:
- Replace
autowidth
andautoheight
arguments withmode
mode
specifies which axes the content can exceed the viewport's dimensions.mode
can be one of the following:framework.OFFSETTED_VIEWPORT_MODE_HORIZONTAL_VERTICAL
framework.OFFSETTED_VIEWPORT_MODE_HORIZONTAL
framework.OFFSETTED_VIEWPORT_MODE_VERTICAL
An error with a descriptive message will be provided if an invalid value is provided.
Scrollbars will be provided in dimensions that exceed the viewport's bounds and have been clipped.
mode
is immutable.
Bugs fixed:
- Viewport not clipping to its bounds
- Viewport scrollbars not receiving input when the content in the viewport is interactive
- Draw to Position; all drawing components defer drawing to a
framework:DrawingGroup
framework:TextGroup
now callstext:Draw
instead oftext:DrawForReal
- Many places that wrapped their children in a
framework:TextGroup
now wrap their children in aframework:DrawingGroup
, since it also provides a text group
Bugfixes:
- Fixed missing include for
gl_Blending
that brokeframework:Blending
Misc debug changes:
- Bugfix: No longer attempt to log nil messages
- Displays message in console when debug mode is enabled
- Provide debug information for
framework:ResizableMovableFrame
- Provide debug information for
framework:MovableFrame
- Store responder event in
responder._event
Also updated readme! :)
Displays component borders on-screen, and shows debug info about the component under mouse.
Call frameworkInternal.SetDebugMode(?, false, ?)
in the framework's initialiser to enable.
This delegates the padding, which makes it more flexible.
- iterate v.s. pairs should be faster and have a predictable ordering
- tasking the
SearchDownResponderTree
with the array invert turns out to be save work when reusing, and be a little more predictable.
Leaving unhandled events unclaimed made for a poor interaction experience, when the cursor was clearly over the element.
All base responders now return true
by default, and events that fail to find a child now trigger for the initial responder they were provided.
Adds Menu
, MenuAnchor
, RightClickMenuAnchor
, MultiOptionBox
, CelledVerticalStack
, and Cell
.
See in-code documentation for more details.
- Rename
char
toutf8char
inTextInput
- Rename
unicode
toutf32char
inKeyPress
andKeyRelease
- Add
scanCode
andactionList
arguments inKeyPress
andKeyRelease
- added
Internal.debugMode.noRasterizer
to specifically disable rasterizers - Disabled
LogDrawCall
default print spam; instead, we'll rely on external debugging tools overriding this call. - Rename
component._debugIdentifier
tocomponent._debugTypeIdentifier
- Add
component._debugUniqueIdentifier
, which will be a unique integer identifying the component. - Add
Internal.DebugInfo
, returned bywidget:DebugInfo()
that allows components to report debug information. Please only do so when debug mode is enabled. - Default to all debug modes off. PLEASE DO NOT COMMIT ANY CHANGES THAT SET ANY DEBUG MODES TRUE, AS THEY SIGNIFICANTLY IMPACT PERFORMANCE.
Now auto-invalidates on resize, move, and correctly invalidates on viewportDidChange.
Uses framework:Dimension
for stroke.width
Call framework:GetElement(key)
and element:Draw()
to get an element and draw it, respectively.
Removed the trickery in HorizontalStack
& VerticalStack
: Hungry Stacks allow positioning of predictably-sized views before and after a component of unbounded size, and layout the unbounded component last, making sure it always knows exactly how much space it's got.
Versioning is now more thorough: you can drag-and-drop multiple frameworks in beside each other and have them (mostly) work. They won't be able to steal focus from each other, for example, but it's a start. Ideally you won't have to constantly bump the versions on all the widgets, but I haven't figured out something to resolve that just yet.
(Almost) every component is now in its own file, to make navigating & adding new stuff a bunch easier.
Various un-committed tweaks (mostly commented/unused stuff) crept in here, and will have to be cleaned up. Behaviour should not have changed, other than specific changes to make such a reorg possible.
A framework-local environment - framework.Internal
is provided during initialisation. Cache this (local Internal = Internal
if a component needs to access this table throughout its use.) This allows inter-component communication of values, or communication of internal values to the widget file.
Config data is saved/stored to/from framework.Internal.ConfigData
. I'd highly recommend each component store their data under in a table keyed into ConfigData
with their component name - e.g. framework.Internal.ConfigData.MovableFrame
.
Framework-external dependencies are provided during initialisation as framework.Include
. Again, anything needed from this table throughout the component's use must be cached.
Various constants that were used in various places are now stored directly in the framework - e.g. framework.color
, framework.stroke
, framework.dimension
.
Debug:
- All debug functions are now available externally.
- Debug mode is now enabled by calling
Internal.SetDebugMode(general, draw)
directly after framework initialisation. This includes a new and improved identifier system that automatically adds a debugIdentifier with a table's type, and also automatically adds reporting for draw and layout calls.
Added framework:WrappingText
! WrappingText
stores a rawString
and displays a displayString
, with an interface to convert character between them. Text colouring is also supported: override WrappingText:ColoredString(string)
to annotate the raw string (e.g. for code syntax highlighting). Support for return-based newlines was added (wrappingText:editReturn()
) and indices for delete + backspace were fixed.
framework:TextEntry
now wraps a WrappingText
. Provide 1
as a value for maxLines
to prevent wrapping. Click-and-drag selection is now supported, and block selection is now shown while deselected.
Text is now a custom WrappingText
that drops the constantWidth
, constantHeight
and watch
options. constantHeight
is replaced with maxLines
, and width restrictions will have to be provided by a wrapping container. Text:GetString()
is still available, simply returning WrappingText:GetRawString()
. (NB watch
appears to already have been disabled.)
funcs.lua:
Added string:lines()
, string:inserting(newString, index)
, string:unEscaped(showNewlines)
.
unEscaped
is primarily for debug purposes.
...
View elements no longer take a number for constant dimensions; instead, they accept a function which will return a value. Further internal optimisations to be made, and possibly allowance for providing element-specific scalings. Currently, scaling is provided based on a single constant, and relative to 1080p. Also tweaked changelog formatting because why not :)
Added framework:Blending
; wraps decorations (which execute GL calls) in a gl.Blending call, resetting to default after.
Improved mouse over handling to provide calls for enter & leave
Added TextGroups
Rasterizer & PrimaryFrame body restricted to element:SetBody(newBody)