Raise/lower: I thought this was harder, but because we're not doing arbitrary insert/delete, we can just use an integer stacking index! We get 9,007,199,254,740,990 positive and negative integers, which we can assume is larger than even the number of raise/lower operations on a page.
[ ] Maintain a min and max order index (for each page I guess).
[ ] Move to front: increment max and set order to that. Move to back: decrement min and set order to that.
[ ] Moving forward/back one: just swap your order with your neighbor. Only change the order index of two objects. More generally, swapping with another object is easy. So this lets you do something like "move down one level relative to things that overlap me" which I think is what a user wants: Moving n objects up one step requires n+1 changes... not terrible. Ideally should be one big history event though (#181).
[ ] Keyboard shortcuts: Inkscape uses home/end/page-up/down, which is nice and simple (and generalizes well to layers) but we do currently use page-up/down for actual pages. Illustrator uses ctrl-[/] and ctrl-shift-[/]. I could see using [/] and {/} (without ctrl).
[ ] UI buttons probably want to be an overlay on the selection, as this is possible only when selecting. So probably need #184 first.
[ ] Bootstrapping: Automatically index all existing objects by natural database order? Yes. Related:
[x] Do we need to worry about identical indices? Yes, need to avoid for non-move-to-front/back operations. (Can always move the identical objects off the shared index. Oh, but then you'll have more duplicates, so rather annoying to get around.) Related:
[ ] Should we use objectEdit (and allow directly updating indices) or a new operation objectOrder? Latter seems safer, especially if we want to avoid duplicate indices. We can specify the object whose index we want to swap with, which preserves no duplication even if other order operations get played before/after us. Needs to be atomic, via withTransaction.
[ ] Every object gets a new order field.
[ ] objectNew needs to use and increment max. This can be done atomically via findOneAndUpdate.
[ ] Rendering needs to re-order SVG according to index. This will fix an existing bug where different users can see a different stacking order. (If they create objects near the same time, the local creation will be a little earlier.)
[ ] Undo should probably restore old order index if it's available, and otherwise assign new max. I.e. objectNew can specify an order index, but it's ignored if that index is taken. (Needs to be done atomically, probably via withTransaction.) This breaks the old ordering workaround, but is more intuitive behavior: delete + undo, or undo + redo, will preserve the stacking order.
Layers:
[ ] List of layers (toggled?) -- at page level?
[ ] Images by default go into a separate Images layer below drawing
[ ] "Move selection to this layer" button
[ ] Add layer
[ ] Re-order layers
[ ] Lock layers (like #150)
[ ] Hide layer (local, maybe global? or just when following?)
[ ] Duplicating/pasting preserves layers, creating layers with same name if they don't exist
[ ] If all objects are in same layer, maybe just paste to current layer. Except maybe for images from Images layer...
[ ] Special grid layer so can decide what it's on top of
Here's a sketch of a simpler interface with unnamed layers and local show/hide:
Raise/lower: I thought this was harder, but because we're not doing arbitrary insert/delete, we can just use an integer stacking index! We get 9,007,199,254,740,990 positive and negative integers, which we can assume is larger than even the number of raise/lower operations on a page.
[
/]
and ctrl-shift-[
/]
. I could see using[
/]
and{
/}
(without ctrl).objectEdit
(and allow directly updating indices) or a new operationobjectOrder
? Latter seems safer, especially if we want to avoid duplicate indices. We can specify the object whose index we want to swap with, which preserves no duplication even if other order operations get played before/after us. Needs to be atomic, viawithTransaction
.order
field.objectNew
needs to use and increment max. This can be done atomically viafindOneAndUpdate
.objectNew
can specify an order index, but it's ignored if that index is taken. (Needs to be done atomically, probably viawithTransaction
.) This breaks the old ordering workaround, but is more intuitive behavior: delete + undo, or undo + redo, will preserve the stacking order.Layers:
Here's a sketch of a simpler interface with unnamed layers and local show/hide: