|
wxMaxima
|
The layout/recalculation engine of a worksheet. More...
#include <WorksheetLayout.h>
Data Structures | |
| struct | ScrollAnchor |
| The point of the worksheet the cursor sits at, for ArmScrollCompensation(). More... | |
Public Member Functions | |
| WorksheetLayout (Configuration *config, WorksheetView &view, std::function< GroupCell *()> getTree, std::function< GroupCell *()> getLastCell) | |
| Construct the engine. | |
| WorksheetLayout (const WorksheetLayout &)=delete | |
| WorksheetLayout & | operator= (const WorksheetLayout &)=delete |
| void | RequestRecalculation (Cell *start) |
| Schedule a recalculation of the worksheet starting with the cell start. | |
| void | RequestFullRecalculation () |
| Schedule a recalculation of the whole worksheet. | |
| bool | RecalculateIfNeeded (bool timeout=false, long timeSliceMs=50) |
| Perform the scheduled recalculation, if one is pending. | |
| void | AdjustSize () |
| Adjust the virtual size and scrollbars to the document's extent. | |
| void | GetMaxPoint (int *width, int *height) |
| Get the coordinates of the bottom right point of the worksheet. | |
| void | UpdateConfigurationClientSize () |
| Inform the configuration about the view's current client size. | |
| int | GroupCellWidthWithMargins (int cellWidth) const |
| The horizontal space a group cell of the given width occupies. | |
| int | GetScrollUnit () const |
| The scroll granularity (device px per scroll unit) AdjustSize() last applied. | |
| void | RequestAdjustSize () |
| Flag the virtual (scroll) size as needing re-adjustment. | |
| void | CancelPendingRecalculation () |
| Drop any pending recalculation (e.g. when the document is cleared). | |
| void | SetScrollAnchorCallback (std::function< ScrollAnchor()> callback) |
| Tells the engine where the cursor currently is. | |
| void | ArmScrollCompensation () |
| Keep the cursor still on screen across the next layout pass. | |
| void | ArmScrollCompensation (GroupCell *cell) |
Keep cell's top still on screen across the next layout pass. | |
| bool | ScrollCompensationArmed () const |
| Is a scroll compensation waiting for the next layout pass to finish? | |
| int | GetLastCellsVisited () const |
| GroupCells walked by the most recent RecalculateIfNeeded() pass (visited includes cheap reposition-only cells; recalculated counts only the cells that actually needed the expensive re-layout). Exposed for tests and diagnostics: a localized change should recalculate very few cells, so a large count on a small edit signals an over-broad recalculation. | |
| int | GetLastCellsRecalculated () const |
Static Public Member Functions | |
| static GroupCell * | FirstGroupReachingBelow (GroupCell *tree, int y) |
The first group cell of tree that reaches below document y y. | |
| static int | AnchorY (const ScrollAnchor &anchor) |
The document y of anchor's cursor position. | |
The layout/recalculation engine of a worksheet.
Talks to the cell tree via the callbacks handed to the constructor, to the window via a WorksheetView and to the Configuration for metrics and the canvas size. Worksheet holds one instance and forwards its layout entry points here; the headless unit test drives an instance without any window.
| WorksheetLayout::WorksheetLayout | ( | Configuration * | config, |
| WorksheetView & | view, | ||
| std::function< GroupCell *()> | getTree, | ||
| std::function< GroupCell *()> | getLastCell | ||
| ) |
Construct the engine.
| config | The Configuration supplying metrics, the canvas size and the recalculation drawing context. |
| view | The window surface (real Worksheet or a test mock). Held by reference: must outlive this object. |
| getTree | Returns the first GroupCell of the worksheet (or null). |
| getLastCell | Returns the last GroupCell of the worksheet (or null). |
| void WorksheetLayout::AdjustSize | ( | ) |
Adjust the virtual size and scrollbars to the document's extent.
Defers (via RequestAdjustSize()) while a recalculation is still pending, since the cell positions it reads would be stale - see the implementation comment for the full story.
|
static |
The document y of anchor's cursor position.
The top of its cell, or the bottom for the horizontal cursor. Lays the cell out first if its size has been reset, as reading a reset size gives 0.
| void WorksheetLayout::ArmScrollCompensation | ( | ) |
Keep the cursor still on screen across the next layout pass.
Called just before output is appended to a cell, or removed from it: the cells below it are about to move, the cursor with them if it sits below the changed cell. This remembers where the cursor's cell is now; once the pass has laid everything out, the view is scrolled by however far that cell moved - to the pixel, see ComputeScrollCompensation() - so the cursor, and everything around it, stays where the user was looking.
Only ever arms once per pass: a second append before the pass has run would measure positions that aren't on screen yet. The caller is expected to only arm if the cursor is visible - scrolling to keep an invisible point still would move the part of the worksheet the user actually is looking at.
| void WorksheetLayout::ArmScrollCompensation | ( | GroupCell * | cell | ) |
Keep cell's top still on screen across the next layout pass.
For when the cursor is out of sight: then the part of the worksheet the user is looking at - of which cell is the topmost group cell - is what must not move. Without it, re-evaluating a cell above the view moved everything in view up when the old output was removed, and down again once the new output arrived; for a plot or anything else slow to compute there was a paint in between, so the view jumped twice.
Unlike ArmScrollCompensation() this doesn't depend on where the cursor is, so it isn't dropped if the cursor moves before the pass has run. Also only ever arms once per pass, and is a no-op if a compensation is armed already.
The first group cell of tree that reaches below document y y.
With the top of the view as y, that is the topmost group cell the user can see at least part of. Cells that haven't been positioned yet are skipped. nullptr if there is none.
| void WorksheetLayout::GetMaxPoint | ( | int * | width, |
| int * | height | ||
| ) |
Get the coordinates of the bottom right point of the worksheet.
Only valid once no recalculation is pending; asserts on that.
|
inline |
The scroll granularity (device px per scroll unit) AdjustSize() last applied.
Worksheet's scroll handlers read it to convert scroll positions to pixels.
| int WorksheetLayout::GroupCellWidthWithMargins | ( | int | cellWidth | ) | const |
The horizontal space a group cell of the given width occupies.
That is the cell's own width plus the equal left and right margins the worksheet reserves around every group cell. Used both when measuring the document width (GetMaxPoint) and while walking the recalculation.
| bool WorksheetLayout::RecalculateIfNeeded | ( | bool | timeout = false, |
| long | timeSliceMs = 50 |
||
| ) |
Perform the scheduled recalculation, if one is pending.
One walk from the scheduled start point drives both modes: with timeout set the pass is time-sliced (yields after timeSliceMs, resuming on the next call); otherwise the whole scheduled range is laid out in one go. Ends by adjusting the virtual size once the cell positions are valid.
|
inline |
Flag the virtual (scroll) size as needing re-adjustment.
Set when a cell changed height (via the callback Worksheet registers on the Configuration, so cells can flag it without depending on the view) or when layout is scheduled; consumed by RecalculateIfNeeded(), which calls AdjustSize() once the cell positions are valid.
| void WorksheetLayout::RequestFullRecalculation | ( | ) |
Schedule a recalculation of the whole worksheet.
For changes that potentially dirty cells at arbitrary positions (zoom, font or configuration changes, window resizes): the dirty range becomes "the first cell to the end of the document", so the next layout pass may not stop early. An operation that changes one known cell should call RequestRecalculation(cell) instead.
| void WorksheetLayout::RequestRecalculation | ( | Cell * | start | ) |
Schedule a recalculation of the worksheet starting with the cell start.
This only records where the next layout pass has to start (it marks the group dirty and extends the pending dirty range [m_recalculateStart, m_recalculateEnd]); it does not size or position any cell. The actual work - and, crucially, AdjustSize() once the cell positions are correct - happens in RecalculateIfNeeded(). Calling AdjustSize() (or otherwise reading cell geometry) right after this, without a RecalculateIfNeeded() in between, reads stale positions.
|
inline |
Tells the engine where the cursor currently is.
Queried by ArmScrollCompensation() and again once the layout pass has run, so a compensation is dropped if the cursor moved in between: the point to keep still is then a different one. Worksheet sets this; without it (the headless tests) no compensation is ever armed.