Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
undo-history.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
6/* Author:
7 * Gustav Broberg <broberg@kth.se>
8 * Abhishek Sharma
9 * Jon A. Cruz <jon@joncruz.org>
10 *
11 * Copyright (C) 2014 Authors
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15#include "undo-history.h"
16
17#include <gtkmm/cellrendererpixbuf.h>
18
19#include "document-undo.h"
20#include "document.h"
21#include "inkscape.h"
22#include "ui/pack.h"
23#include "util/signal-blocker.h"
24
25namespace Inkscape::UI::Dialog {
26
27const CellRendererInt::Filter &CellRendererInt::no_filter = CellRendererInt::NoFilter();
28
30 : DialogBase("/dialogs/undo-history", "UndoHistory"),
31 _event_list_selection(_event_list_view.get_selection())
32{
33 auto const columns = &EventLog::getColumns();
34
35 set_size_request(-1, -1);
36
38 _scrolled_window.set_policy(Gtk::PolicyType::NEVER, Gtk::PolicyType::AUTOMATIC);
39
40 _event_list_view.set_enable_search(false);
41 _event_list_view.set_headers_visible(false);
42
43 auto const icon_renderer = Gtk::make_managed<Gtk::CellRendererPixbuf>();
44 icon_renderer->property_xpad() = 2;
45 icon_renderer->property_width() = 24;
46 int cols_count = _event_list_view.append_column("Icon", *icon_renderer);
47
48 auto const icon_column = _event_list_view.get_column(cols_count - 1);
49 icon_column->add_attribute(icon_renderer->property_icon_name(), columns->icon_name);
50
51 auto const children_renderer = Gtk::make_managed<CellRendererInt>(greater_than_1);
52 children_renderer->property_weight() = 600; // =Pango::WEIGHT_SEMIBOLD (not defined in old versions of pangomm)
53 children_renderer->property_xalign() = 1.0;
54 children_renderer->property_xpad() = 2;
55 children_renderer->property_width() = 24;
56
57 cols_count = _event_list_view.append_column("Children", *children_renderer);
58 auto const children_column = _event_list_view.get_column(cols_count - 1);
59 children_column->add_attribute(children_renderer->property_number(), columns->child_count);
60
61 auto const description_renderer = Gtk::make_managed<Gtk::CellRendererText>();
62 description_renderer->property_ellipsize() = Pango::EllipsizeMode::END;
63
64 cols_count = _event_list_view.append_column("Description", *description_renderer);
65 auto const description_column = _event_list_view.get_column(cols_count - 1);
66 description_column->add_attribute(description_renderer->property_text(), columns->description);
67 description_column->set_resizable();
68 description_column->set_sizing(Gtk::TreeViewColumn::Sizing::AUTOSIZE);
69 description_column->set_min_width (150);
70
71 _event_list_view.set_expander_column( *_event_list_view.get_column(cols_count - 1) );
72
74 _scrolled_window.set_overlay_scrolling(false);
75 // connect EventLog callbacks
77 _event_list_selection->signal_changed().connect(sigc::mem_fun(*this, &Inkscape::UI::Dialog::UndoHistory::_onListSelectionChange));
78
80 _event_list_view.signal_row_expanded().connect(sigc::mem_fun(*this, &Inkscape::UI::Dialog::UndoHistory::_onExpandEvent));
81
83 _event_list_view.signal_row_collapsed().connect(sigc::mem_fun(*this, &Inkscape::UI::Dialog::UndoHistory::_onCollapseEvent));
84}
85
90
92{
94 if (auto document = getDocument()) {
95 g_assert (document->get_event_log() != nullptr);
97 _event_list_view.unset_model();
99 }
100}
101
111
122
123void
125{
126 auto selected = _event_list_selection->get_selected();
127
128 /* If no event is selected in the view, find the right one and select it. This happens whenever
129 * a branch we're currently in is collapsed.
130 */
131 if (!selected) {
132 auto curr_event = _event_log->getCurrEvent();
133 auto const curr_event_parent = curr_event->parent();
134
135 if (curr_event_parent) {
137
138 auto const last = --curr_event_parent->children().end();
139 for (; curr_event != last ; ++curr_event ) {
141 }
142
144
145 _event_log->setCurrEvent(curr_event);
146 _event_list_selection->select(curr_event_parent);
147 } else { // this should not happen
148 _event_list_selection->select(curr_event);
149 }
150
151 return;
152 }
153
154 /* Selecting a collapsed parent event is equal to selecting the last child
155 * of that parent's branch.
156 */
157 if ( !selected->children().empty() &&
158 !_event_list_view.row_expanded(_event_list_store->get_path(selected)) )
159 {
160 selected = selected->children().end();
161 --selected;
162 }
163
164 // An event before the current one has been selected. Undo to the selected event.
165 auto last_selected = _event_log->getCurrEvent();
166 if ( _event_list_store->get_path(selected) <
167 _event_list_store->get_path(last_selected) )
168 {
170
171 while ( selected != last_selected ) {
173
174 if ( last_selected->parent() &&
175 last_selected == last_selected->parent()->children().begin() )
176 {
177 last_selected = last_selected->parent();
179 } else {
180 --last_selected;
181 if ( !last_selected->children().empty() ) {
182 _event_log->setCurrEventParent(last_selected);
183 last_selected = last_selected->children().end();
184 --last_selected;
185 }
186 }
187 }
188
190
192 } else { // An event after the current one has been selected. Redo to the selected event.
194
195 while (last_selected && selected != last_selected ) {
197
198 if ( !last_selected->children().empty() ) {
199 _event_log->setCurrEventParent(last_selected);
200 last_selected = last_selected->children().begin();
201 } else {
202 ++last_selected;
203
204 if ( last_selected->parent() &&
205 last_selected == last_selected->parent()->children().end() )
206 {
207 last_selected = last_selected->parent();
208 ++last_selected;
210 }
211 }
212 }
213
215
216 }
217
218 _event_log->setCurrEvent(selected);
220}
221
222void
223UndoHistory::_onExpandEvent(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &/*path*/)
224{
225 if ( iter == _event_list_selection->get_selected() ) {
227 }
228}
229
230void
231UndoHistory::_onCollapseEvent(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &/*path*/)
232{
233 // Collapsing a branch we're currently in is equal to stepping to the last event in that branch
234 auto const curr_event_parent = _event_log->getCurrEvent();
235 if (iter == curr_event_parent) {
237
239
240 auto curr_event = curr_event_parent->children().begin();
241 auto const last = --curr_event_parent->children().end();
242 for (; curr_event != last ; ++curr_event) {
244 }
245
247
248 _event_log->setCurrEvent(curr_event);
249 _event_log->setCurrEventParent(curr_event_parent);
250 _event_list_selection->select(curr_event_parent);
251 }
252}
253
255
256} // namespace Inkscape::UI::Dialog
257
258/*
259 Local Variables:
260 mode:c++
261 c-file-style:"stroustrup"
262 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
263 indent-tabs-mode:nil
264 fill-column:99
265 End:
266*/
267// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
static gboolean redo(SPDocument *document)
static gboolean undo(SPDocument *document)
void addDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
Connect with a TreeView.
void removeDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections)
Disconnect from a TreeView.
void blockNotifications(bool status=true)
Definition event-log.h:90
Glib::RefPtr< Gtk::TreeModel > getEventListStore() const
Definition event-log.h:83
void setCurrEventParent(iterator event)
Definition event-log.h:89
void setCurrEvent(iterator event)
Definition event-log.h:88
iterator getCurrEvent() const
Definition event-log.h:85
static const EventModelColumns & getColumns()
DialogBase is the base class for the dialog system.
Definition dialog-base.h:42
SPDocument * getDocument() const
Definition dialog-base.h:83
EventLog::CallbackMap _callback_connections
void _onExpandEvent(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &path)
Glib::RefPtr< Gtk::TreeModel > _event_list_store
Glib::RefPtr< Gtk::TreeSelection > _event_list_selection
static const CellRendererInt::Filter & greater_than_1
void _onCollapseEvent(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &path)
Gtk::ScrolledWindow _scrolled_window
Inkscape::EventLog * get_event_log()
Definition document.h:160
RAII blocker for sigc++ signals.
TODO: insert short description here.
Dialog code.
Definition desktop.h:117
void pack_start(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the start of box.
Definition pack.cpp:141
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
Undo History dialog.