From fe9928bdb4a8de214fd0947a3b28cf052dc9094a Mon Sep 17 00:00:00 2001 From: askmeaboutloom Date: Sun, 29 Sep 2024 02:46:36 +0200 Subject: [PATCH] Add Group View mode Shows the parent group of the current layer in isolation. --- ChangeLog | 2 + src/desktop/mainwindow.cpp | 6 +++ .../libengine/dpengine/layer_routes.c | 36 ++++++++++++++--- .../libengine/dpengine/layer_routes.h | 4 ++ .../libengine/dpengine/local_state.c | 8 +++- .../libengine/dpengine/paint_engine.c | 10 ++++- src/drawdance/libengine/dpengine/renderer.c | 11 +++-- src/drawdance/libengine/dpengine/view_mode.c | 40 +++++++++++++++++-- src/drawdance/libengine/dpengine/view_mode.h | 1 + src/drawdance/rust/bindings.rs | 3 +- 10 files changed, 104 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3afe1702d..59500268a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,8 @@ Unreleased Version 2.2.2-pre * Feature: Extended touch tap gestures, among them two-finger tap to undo, three-finger tap to redo and tap-and-hold to summon the color picker. Can be configured in the preferences under the Touch tab. Thanks InconsolableCellist and many others for suggesting. * Feature: Snap canvas rotation around 0° by default. If you don't want this, you can set the canvas shortcut or touch rotation to "free rotate canvas" instead. * Feature: Show a color preview when picking a color from the canvas. Can be toggled in the tool preferences. + * Fix: In layer view mode, render the layer truly in isolation instead of applying opacities, visibilities or alpha preserve to it. Thanks MachKerman and incoheart for reporting. + * Feature: Add Layer > Group View to show the parent group of the current layer in isolation. Thanks Rylan for suggesting. 2024-08-09 Version 2.2.2-beta.3 * Fix: Use more accurate timers for performance profiles if the platform supports it. diff --git a/src/desktop/mainwindow.cpp b/src/desktop/mainwindow.cpp index 1559af05d..0a91da1f7 100644 --- a/src/desktop/mainwindow.cpp +++ b/src/desktop/mainwindow.cpp @@ -859,6 +859,7 @@ void MainWindow::toggleLayerViewMode() // pressing the shortcut again would have no useful effect anyway. QAction *actions[] = { getAction("layerviewcurrentlayer"), + getAction("layerviewcurrentgroup"), getAction("layerviewcurrentframe"), }; for (QAction *action : actions) { @@ -881,6 +882,8 @@ void MainWindow::updateLayerViewMode() QAction *action; if((action = getAction("layerviewcurrentlayer"))->isChecked()) { mode = DP_VIEW_MODE_LAYER; + } else if((action = getAction("layerviewcurrentgroup"))->isChecked()) { + mode = DP_VIEW_MODE_GROUP; } else if((action = getAction("layerviewcurrentframe"))->isChecked()) { mode = DP_VIEW_MODE_FRAME; } else { @@ -4573,6 +4576,7 @@ void MainWindow::setupActions() QAction *layerViewNormal = makeAction("layerviewnormal", tr("Normal View")).statusTip(tr("Show all layers normally")).noDefaultShortcut().checkable().checked(); QAction *layerViewCurrentLayer = makeAction("layerviewcurrentlayer", tr("Layer View")).statusTip(tr("Show only the current layer")).shortcut("Home").checkable(); + QAction *layerViewCurrentGroup = makeAction("layerviewcurrentgroup", tr("Group View")).statusTip(tr("Show only the current parent layer group")).shortcut("Ctrl+Home").checkable(); QAction *layerViewCurrentFrame = makeAction("layerviewcurrentframe", tr("Frame View")).statusTip(tr("Show only layers in the current frame")).shortcut("Shift+Home").checkable(); QAction *layerUncensor = makeAction("layerviewuncensor", tr("Show Censored Layers")).noDefaultShortcut().checkable(); m_lastLayerViewMode = layerViewNormal; @@ -4581,11 +4585,13 @@ void MainWindow::setupActions() layerViewModeGroup->setExclusive(true); layerViewModeGroup->addAction(layerViewNormal); layerViewModeGroup->addAction(layerViewCurrentLayer); + layerViewModeGroup->addAction(layerViewCurrentGroup); layerViewModeGroup->addAction(layerViewCurrentFrame); QMenu *layerViewMenu = viewmenu->addMenu(tr("Layer View Mode")); layerViewMenu->addAction(layerViewNormal); layerViewMenu->addAction(layerViewCurrentLayer); + layerViewMenu->addAction(layerViewCurrentGroup); layerViewMenu->addAction(layerViewCurrentFrame); viewmenu->addAction(layerUncensor); diff --git a/src/drawdance/libengine/dpengine/layer_routes.c b/src/drawdance/libengine/dpengine/layer_routes.c index 92788c170..8b7b3beb5 100644 --- a/src/drawdance/libengine/dpengine/layer_routes.c +++ b/src/drawdance/libengine/dpengine/layer_routes.c @@ -38,6 +38,7 @@ typedef struct DP_LayerRoutesEntry { UT_hash_handle hh; bool is_group; int layer_id; + DP_LayerRoutesEntry *parent_lre; int index_count; int indexes[]; } DP_LayerRoutesEntry; @@ -56,8 +57,9 @@ DP_LayerRoutes *DP_layer_routes_new(void) return lr; } -static void insert(DP_LayerRoutes *lr, DP_DrawContext *dc, DP_LayerProps *lp, - bool is_group) +static DP_LayerRoutesEntry *insert(DP_LayerRoutes *lr, DP_DrawContext *dc, + DP_LayerProps *lp, bool is_group, + DP_LayerRoutesEntry *parent_lre) { int index_count; int *indexes = DP_draw_context_layer_indexes(dc, &index_count); @@ -66,16 +68,19 @@ static void insert(DP_LayerRoutes *lr, DP_DrawContext *dc, DP_LayerProps *lp, DP_LayerRoutesEntry, indexes, DP_int_to_size(index_count))); lre->layer_id = DP_layer_props_id(lp); lre->is_group = is_group; + lre->parent_lre = parent_lre; lre->index_count = index_count; for (int i = 0; i < index_count; ++i) { lre->indexes[i] = indexes[i]; } HASH_ADD_INT(lr->entries, layer_id, lre); + return lre; } static void index_layers(DP_LayerRoutes *lr, DP_DrawContext *dc, - DP_LayerPropsList *lpl) + DP_LayerPropsList *lpl, + DP_LayerRoutesEntry *parent_lre) { int count = DP_layer_props_list_count(lpl); DP_draw_context_layer_indexes_push(dc); @@ -83,9 +88,9 @@ static void index_layers(DP_LayerRoutes *lr, DP_DrawContext *dc, DP_draw_context_layer_indexes_set(dc, i); DP_LayerProps *lp = DP_layer_props_list_at_noinc(lpl, i); DP_LayerPropsList *child_lpl = DP_layer_props_children_noinc(lp); - insert(lr, dc, lp, child_lpl); + DP_LayerRoutesEntry *lre = insert(lr, dc, lp, child_lpl, parent_lre); if (child_lpl) { - index_layers(lr, dc, child_lpl); + index_layers(lr, dc, child_lpl, lre); } } DP_draw_context_layer_indexes_pop(dc); @@ -98,7 +103,7 @@ DP_LayerRoutes *DP_layer_routes_new_index(DP_LayerPropsList *lpl, DP_ASSERT(dc); DP_LayerRoutes *lr = DP_layer_routes_new(); DP_draw_context_layer_indexes_clear(dc); - index_layers(lr, dc, lpl); + index_layers(lr, dc, lpl, NULL); return lr; } @@ -145,6 +150,19 @@ DP_LayerRoutesEntry *DP_layer_routes_search(DP_LayerRoutes *lr, int layer_id) return lre; } +int DP_layer_routes_search_parent_id(DP_LayerRoutes *lr, int layer_id) +{ + DP_ASSERT(lr); + DP_LayerRoutesEntry *child_lre = DP_layer_routes_search(lr, layer_id); + if (child_lre) { + DP_LayerRoutesEntry *lre = DP_layer_routes_entry_parent(child_lre); + if (lre) { + return lre->layer_id; + } + } + return 0; +} + struct DP_MakeLayerOrderContext { int source_id; @@ -457,6 +475,12 @@ void DP_layer_routes_entry_children(DP_LayerRoutesEntry *lre, get_children(lre->index_count, lre->indexes, cs, out_ll, out_lpl); } +DP_LayerRoutesEntry *DP_layer_routes_entry_parent(DP_LayerRoutesEntry *lre) +{ + DP_ASSERT(lre); + return lre->parent_lre; +} + uint16_t DP_layer_routes_entry_parent_opacity(DP_LayerRoutesEntry *lre, DP_CanvasState *cs) { diff --git a/src/drawdance/libengine/dpengine/layer_routes.h b/src/drawdance/libengine/dpengine/layer_routes.h index 1a6b645c0..7bb989cb5 100644 --- a/src/drawdance/libengine/dpengine/layer_routes.h +++ b/src/drawdance/libengine/dpengine/layer_routes.h @@ -67,6 +67,8 @@ void DP_layer_routes_decref_nullable(DP_LayerRoutes *lr_or_null); DP_LayerRoutesEntry *DP_layer_routes_search(DP_LayerRoutes *lr, int layer_id); +int DP_layer_routes_search_parent_id(DP_LayerRoutes *lr, int layer_id); + DP_Message *DP_layer_routes_layer_order_make(DP_CanvasState *cs, unsigned int context_id, int source_id, int target_id, @@ -105,6 +107,8 @@ void DP_layer_routes_entry_children(DP_LayerRoutesEntry *lre, DP_CanvasState *cs, DP_LayerList **out_ll, DP_LayerPropsList **out_lpl); +DP_LayerRoutesEntry *DP_layer_routes_entry_parent(DP_LayerRoutesEntry *lre); + uint16_t DP_layer_routes_entry_parent_opacity(DP_LayerRoutesEntry *lre, DP_CanvasState *cs); diff --git a/src/drawdance/libengine/dpengine/local_state.c b/src/drawdance/libengine/dpengine/local_state.c index 2a106d36f..d57acb59e 100644 --- a/src/drawdance/libengine/dpengine/local_state.c +++ b/src/drawdance/libengine/dpengine/local_state.c @@ -290,6 +290,7 @@ static void handle_view_mode(DP_LocalState *ls, DP_MsgLocalChange *mlc) switch (value) { case DP_VIEW_MODE_NORMAL: case DP_VIEW_MODE_LAYER: + case DP_VIEW_MODE_GROUP: case DP_VIEW_MODE_FRAME: { DP_ViewMode view_mode = (DP_ViewMode)value; if (view_mode != ls->view_mode) { @@ -311,8 +312,13 @@ static void handle_active_layer(DP_LocalState *ls, DP_MsgLocalChange *mlc) if (read_int_message(mlc, "active layer", &layer_id)) { if (ls->active_layer_id != layer_id) { ls->active_layer_id = layer_id; - if (ls->view_mode == DP_VIEW_MODE_LAYER) { + switch (ls->view_mode) { + case DP_VIEW_MODE_LAYER: + case DP_VIEW_MODE_GROUP: notify_view_invalidated(ls, true, 0); + break; + default: + break; } } } diff --git a/src/drawdance/libengine/dpengine/paint_engine.c b/src/drawdance/libengine/dpengine/paint_engine.c index 461c71ab6..354c2bad2 100644 --- a/src/drawdance/libengine/dpengine/paint_engine.c +++ b/src/drawdance/libengine/dpengine/paint_engine.c @@ -1697,11 +1697,16 @@ static DP_CanvasState *apply_local_background_tile(DP_PaintEngine *pe, } } -static int get_only_layer_id(DP_LocalState *ls) +static int get_only_layer_id(DP_LocalState *ls, DP_CanvasState *cs) { switch (DP_local_state_view_mode(ls)) { case DP_VIEW_MODE_LAYER: return DP_local_state_active_layer_id(ls); + case DP_VIEW_MODE_GROUP: { + DP_LayerRoutes *lr = DP_canvas_state_layer_routes_noinc(cs); + return DP_layer_routes_search_parent_id( + lr, DP_local_state_active_layer_id(ls)); + } default: return 0; } @@ -1719,7 +1724,8 @@ emit_changes(DP_PaintEngine *pe, DP_CanvasState *prev, DP_CanvasState *cs, DP_PaintEngineCursorMovedFn cursor_moved, void *user) { DP_CanvasDiff *diff = pe->diff; - DP_canvas_state_diff(cs, prev, diff, get_only_layer_id(pe->local_state)); + DP_canvas_state_diff(cs, prev, diff, + get_only_layer_id(pe->local_state, cs)); DP_renderer_apply(pe->renderer, cs, pe->local_state, diff, pe->local_view.layers_can_decrease_opacity, pe->local_view.checker_color1, diff --git a/src/drawdance/libengine/dpengine/renderer.c b/src/drawdance/libengine/dpengine/renderer.c index e470fe893..03b307f13 100644 --- a/src/drawdance/libengine/dpengine/renderer.c +++ b/src/drawdance/libengine/dpengine/renderer.c @@ -355,9 +355,10 @@ DP_Renderer *DP_renderer_new(int thread_count, bool checker, renderer->checker_color1 = checker_color1; renderer->checker_color2 = checker_color2; renderer->checker = - checker ? DP_transient_tile_new_checker( - 0, DP_pixel8_to_15(checker_color1), DP_pixel8_to_15(checker_color2)) - : NULL; + checker + ? DP_transient_tile_new_checker(0, DP_pixel8_to_15(checker_color1), + DP_pixel8_to_15(checker_color2)) + : NULL; renderer->cs = DP_canvas_state_new(); renderer->checkers_visible = false; renderer->xtiles = 0; @@ -465,6 +466,7 @@ static bool local_state_params_differ(DP_RendererLocalState *rls, case DP_VIEW_MODE_NORMAL: return false; case DP_VIEW_MODE_LAYER: + case DP_VIEW_MODE_GROUP: return rls->active != DP_local_state_active_layer_id(ls); case DP_VIEW_MODE_FRAME: return rls->active != DP_local_state_active_frame_index(ls) @@ -487,6 +489,9 @@ static DP_RendererLocalState clone_local_state(DP_LocalState *ls) case DP_VIEW_MODE_LAYER: return (DP_RendererLocalState){ DP_VIEW_MODE_LAYER, DP_local_state_active_layer_id(ls), NULL}; + case DP_VIEW_MODE_GROUP: + return (DP_RendererLocalState){ + DP_VIEW_MODE_GROUP, DP_local_state_active_layer_id(ls), NULL}; case DP_VIEW_MODE_FRAME: return (DP_RendererLocalState){ DP_VIEW_MODE_FRAME, DP_local_state_active_frame_index(ls), diff --git a/src/drawdance/libengine/dpengine/view_mode.c b/src/drawdance/libengine/dpengine/view_mode.c index 4e90b8d43..75f0cc897 100644 --- a/src/drawdance/libengine/dpengine/view_mode.c +++ b/src/drawdance/libengine/dpengine/view_mode.c @@ -316,6 +316,12 @@ DP_ViewModeFilter DP_view_mode_filter_make(DP_ViewModeBuffer *vmb, return make_normal_filter(); case DP_VIEW_MODE_LAYER: return make_layer_filter(layer_id); + case DP_VIEW_MODE_GROUP: { + DP_LayerRoutes *lr = DP_canvas_state_layer_routes_noinc(cs); + int group_id = DP_layer_routes_search_parent_id(lr, layer_id); + return group_id > 0 ? make_layer_filter(group_id) + : make_normal_filter(); + } case DP_VIEW_MODE_FRAME: return make_frame_filter(vmb, cs, frame_index, oss, TYPE_FRAME_MANUAL); default: @@ -687,16 +693,37 @@ static bool pick_normal(DP_CanvasState *cs, int x, int y, out_pick); } +static bool pick_lre(DP_LayerRoutesEntry *lre, DP_CanvasState *cs, int x, int y, + DP_ViewModePick *out_pick) +{ + if (lre) { + DP_LayerListEntry *lle = DP_layer_routes_entry_layer(lre, cs); + DP_LayerProps *lp = DP_layer_routes_entry_props(lre, cs); + return pick_entry(lle, lp, x, y, out_pick); + } + else { + return false; + } +} + static bool pick_layer(DP_CanvasState *cs, DP_LocalState *ls, int x, int y, DP_ViewModePick *out_pick) { DP_LayerRoutes *lr = DP_canvas_state_layer_routes_noinc(cs); DP_LayerRoutesEntry *lre = DP_layer_routes_search(lr, DP_local_state_active_layer_id(ls)); - if (lre) { - DP_LayerListEntry *lle = DP_layer_routes_entry_layer(lre, cs); - DP_LayerProps *lp = DP_layer_routes_entry_props(lre, cs); - return pick_entry(lle, lp, x, y, out_pick); + return pick_lre(lre, cs, x, y, out_pick); +} + +static bool pick_group(DP_CanvasState *cs, DP_LocalState *ls, int x, int y, + DP_ViewModePick *out_pick) +{ + DP_LayerRoutes *lr = DP_canvas_state_layer_routes_noinc(cs); + DP_LayerRoutesEntry *child_lre = + DP_layer_routes_search(lr, DP_local_state_active_layer_id(ls)); + if (child_lre) { + DP_LayerRoutesEntry *lre = DP_layer_routes_entry_parent(child_lre); + return pick_lre(lre, cs, x, y, out_pick); } else { return false; @@ -754,6 +781,11 @@ DP_ViewModePick DP_view_mode_pick(DP_CanvasState *cs, DP_LocalState *ls, int x, return pick; } break; + case DP_VIEW_MODE_GROUP: + if (pick_group(cs, ls, x, y, &pick)) { + return pick; + } + break; case DP_VIEW_MODE_FRAME: if (pick_frame(cs, ls, x, y, &pick)) { return pick; diff --git a/src/drawdance/libengine/dpengine/view_mode.h b/src/drawdance/libengine/dpengine/view_mode.h index 5f38e5c46..65f7b008d 100644 --- a/src/drawdance/libengine/dpengine/view_mode.h +++ b/src/drawdance/libengine/dpengine/view_mode.h @@ -35,6 +35,7 @@ typedef struct DP_LocalState DP_LocalState; typedef enum DP_ViewMode { DP_VIEW_MODE_NORMAL, DP_VIEW_MODE_LAYER, + DP_VIEW_MODE_GROUP, DP_VIEW_MODE_FRAME, } DP_ViewMode; diff --git a/src/drawdance/rust/bindings.rs b/src/drawdance/rust/bindings.rs index e29656476..ccb9a2a5e 100644 --- a/src/drawdance/rust/bindings.rs +++ b/src/drawdance/rust/bindings.rs @@ -5088,7 +5088,8 @@ pub struct DP_LocalState { } pub const DP_VIEW_MODE_NORMAL: DP_ViewMode = 0; pub const DP_VIEW_MODE_LAYER: DP_ViewMode = 1; -pub const DP_VIEW_MODE_FRAME: DP_ViewMode = 2; +pub const DP_VIEW_MODE_GROUP: DP_ViewMode = 2; +pub const DP_VIEW_MODE_FRAME: DP_ViewMode = 3; pub type DP_ViewMode = ::std::os::raw::c_uint; #[repr(C)] #[derive(Debug, Copy, Clone)]