1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
/** @file
* @brief A dialog for CSS selectors
*/
/* Authors:
* Kamalpreet Kaur Grewal
* Tavmjong Bah
*
* Copyright (C) Kamalpreet Kaur Grewal 2016 <grewalkamal005@gmail.com>
* Copyright (C) Tavmjong Bah 2017 <tavmjong@free.fr>
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#ifndef STYLEDIALOG_H
#define STYLEDIALOG_H
#include <ui/widget/panel.h>
#include <gtkmm/treeview.h>
#include <gtkmm/treestore.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/dialog.h>
#include <gtkmm/treeselection.h>
#include <gtkmm/paned.h>
#include "ui/dialog/desktop-tracker.h"
#include "ui/dialog/cssdialog.h"
#include "xml/helper-observer.h"
namespace Inkscape {
namespace UI {
namespace Dialog {
/**
* @brief The StyleDialog class
* A list of CSS selectors will show up in this dialog. This dialog allows one to
* add and delete selectors. Elements can be added to and removed from the selectors
* in the dialog. Selection of any selector row selects the matching objects in
* the drawing and vice-versa. (Only simple selectors supported for now.)
*
* This class must keep two things in sync:
* 1. The text node of the style element.
* 2. The Gtk::TreeModel.
*/
class StyleDialog : public Widget::Panel {
public:
~StyleDialog() override;
static StyleDialog &getInstance() { return *new StyleDialog(); }
private:
// No default constructor, noncopyable, nonassignable
StyleDialog();
StyleDialog(StyleDialog const &d) = delete;
StyleDialog operator=(StyleDialog const &d) = delete;
// Monitor <style> element for changes.
class NodeObserver;
// Monitor all objects for addition/removal/attribute change
class NodeWatcher;
std::vector<StyleDialog::NodeWatcher*> _nodeWatchers;
void _nodeAdded( Inkscape::XML::Node &repr );
void _nodeRemoved( Inkscape::XML::Node &repr );
void _nodeChanged( Inkscape::XML::Node &repr );
// Data structure
class ModelColumns : public Gtk::TreeModel::ColumnRecord {
public:
ModelColumns() {
add(_colSelector);
add(_colIsSelector);
add(_colObj);
add(_colProperties);
}
Gtk::TreeModelColumn<Glib::ustring> _colSelector; // Selector or matching object id.
Gtk::TreeModelColumn<bool> _colIsSelector; // Selector row or child object row.
Gtk::TreeModelColumn<std::vector<SPObject *> > _colObj; // List of matching objects.
Gtk::TreeModelColumn<Glib::ustring> _colProperties; // List of properties.
};
ModelColumns _mColumns;
// Override Gtk::TreeStore to control drag-n-drop (only allow dragging and dropping of selectors).
// See: https://developer.gnome.org/gtkmm-tutorial/stable/sec-treeview-examples.html.en
//
// TreeStore implements simple drag and drop (DND) but there appears no way to know when a DND
// has been completed (other than doing the whole DND ourselves). As a hack, we use
// on_row_deleted to trigger write of style element.
class TreeStore : public Gtk::TreeStore {
protected:
TreeStore();
bool row_draggable_vfunc(const Gtk::TreeModel::Path& path) const override;
bool row_drop_possible_vfunc(const Gtk::TreeModel::Path& path,
const Gtk::SelectionData& selection_data) const override;
void on_row_deleted(const TreeModel::Path& path) override;
public:
static Glib::RefPtr<StyleDialog::TreeStore> create(StyleDialog *styledialog);
private:
StyleDialog *_styledialog;
};
// TreeView
Gtk::TreeView _treeView;
Glib::RefPtr<TreeStore> _store;
// Widgets
Gtk::Paned _paned;
Gtk::Box _mainBox;
Gtk::Box _buttonBox;
Gtk::ScrolledWindow _scrolledWindow;
Gtk::Button* del;
Gtk::Button* create;
CssDialog *_cssPane;
// Reading and writing the style element.
Inkscape::XML::Node *_getStyleTextNode();
void _readStyleElement();
void _writeStyleElement();
// Update watchers
void _addWatcherRecursive(Inkscape::XML::Node *node);
void _updateWatchers();
// Manipulate Tree
void _addToSelector(Gtk::TreeModel::Row row);
void _removeFromSelector(Gtk::TreeModel::Row row);
Glib::ustring _getIdList(std::vector<SPObject *>);
std::vector<SPObject *> _getObjVec(Glib::ustring selector);
void _insertClass(const std::vector<SPObject *>& objVec, const Glib::ustring& className);
void _selectObjects(int, int);
void _updateCSSPanel();
// Variables
bool _updating; // Prevent cyclic actions: read <-> write, select via dialog <-> via desktop
Inkscape::XML::Node *_textNode; // Track so we know when to add a NodeObserver.
// Signals and handlers - External
sigc::connection _document_replaced_connection;
sigc::connection _desktop_changed_connection;
sigc::connection _selection_changed_connection;
void _handleDocumentReplaced(SPDesktop* desktop, SPDocument *document);
void _handleDesktopChanged(SPDesktop* desktop);
void _handleSelectionChanged();
DesktopTracker _desktopTracker;
Inkscape::XML::SignalObserver _objObserver; // Track object in selected row (for style change).
// Signal and handlers - Internal
void _addSelector();
void _delSelector();
bool _handleButtonEvent(GdkEventButton *event);
void _buttonEventsSelectObjs(GdkEventButton *event);
void _selectRow(); // Select row in tree when selection changed.
void _objChanged();
// Signal handlers for CssDialog
void _handleProp( const Glib::ustring& path, const Glib::ustring& new_text);
void _handleSheet(const Glib::ustring& path, const Glib::ustring& new_text);
void _handleAttr( const Glib::ustring& path, const Glib::ustring& new_text);
bool _delProperty(GdkEventButton *event);
// GUI
void _styleButton(Gtk::Button& btn, char const* iconName, char const* tooltip);
};
} // namespace Dialogc
} // namespace UI
} // namespace Inkscape
#endif // STYLEDIALOG_H
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
|