]> Shamusworld >> Repos - architektonas/blob - src/layerwidget.cpp
4c9dd93ff73db823c0621daca42d6103b7b19636
[architektonas] / src / layerwidget.cpp
1 // layerwidget.cpp: Layer add/remove/use widget
2 //
3 // Part of the Architektonas Project
4 // (C) 2011 Underground Software
5 // See the README and GPLv3 files for licensing and warranty information
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  07/11/2013  Created this file
12 //
13
14 #include "layerwidget.h"
15 #include "global.h"
16 #include "layeritemwidget.h"
17
18
19 LayerWidget::LayerWidget(void): QWidget(),
20         addLayer(new QToolButton), removeLayer(new QToolButton),
21         editLayer(new QToolButton), layerUp(new QToolButton),
22         layerDown(new QToolButton), list(new QListWidget)
23 {
24         QListWidgetItem * qlwi = new QListWidgetItem(list);
25         LayerItemWidget * liw = new LayerItemWidget("Background", false, false, qlwi);
26         list->setItemWidget(qlwi, liw);
27
28         addLayer->setIcon(QIcon(":/res/layer-add.png"));
29         removeLayer->setIcon(QIcon(":/res/layer-delete.png"));
30         editLayer->setIcon(QIcon(":/res/layer-edit.png"));
31         layerUp->setIcon(QIcon(":/res/layer-up.png"));
32         layerDown->setIcon(QIcon(":/res/layer-down.png"));
33
34         addLayer->setToolTip(tr("Add layer"));
35         removeLayer->setToolTip(tr("Remove layer"));
36         editLayer->setToolTip(tr("Edit layer"));
37         layerUp->setToolTip(tr("Move layer up"));
38         layerDown->setToolTip(tr("Move layer down"));
39
40         QHBoxLayout * hbox1 = new QHBoxLayout;
41         hbox1->addWidget(addLayer);
42         hbox1->addWidget(removeLayer);
43         hbox1->addWidget(editLayer);
44         hbox1->addWidget(layerUp);
45         hbox1->addWidget(layerDown);
46         hbox1->addStretch();
47
48         QVBoxLayout * mainLayout = new QVBoxLayout;
49         mainLayout->addWidget(list);
50         mainLayout->addLayout(hbox1);
51
52         setLayout(mainLayout);
53
54         connect(list, SIGNAL(currentRowChanged(int)), this, SLOT(HandleLayerSelected(int)));
55         connect(list, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(HandleDblClick(QListWidgetItem *)));
56         connect(addLayer, SIGNAL(clicked()), this, SLOT(AddLayer()));
57         connect(removeLayer, SIGNAL(clicked()), this, SLOT(DeleteLayer()));
58         connect(editLayer, SIGNAL(clicked()), this, SLOT(EditLayer()));
59         connect(layerUp, SIGNAL(clicked()), this, SLOT(MoveLayerUp()));
60         connect(layerDown, SIGNAL(clicked()), this, SLOT(MoveLayerDown()));
61
62         connect(liw, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
63         connect(liw, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
64
65         list->setCurrentRow(0);
66
67         // We set global variables here, since we are 'in charge' of them (mostly)
68         Global::activeLayer = 0;
69         Global::numLayers = 1;
70         Global::layerHidden.clear();
71         Global::layerLocked.clear();
72         Global::layerName.clear();
73         Global::layerHidden.push_back(false);
74         Global::layerLocked.push_back(false);
75         Global::layerName.push_back("Background");
76 }
77
78
79 LayerWidget::~LayerWidget()
80 {
81 }
82
83
84 void LayerWidget::Reload(void)
85 {
86         list->clear();
87
88         for(int i=0; i<Global::numLayers; i++)
89         {
90                 QListWidgetItem * qlwi = new QListWidgetItem();
91                 LayerItemWidget * liw = new LayerItemWidget(Global::layerName[i].c_str(), Global::layerHidden[i], Global::layerLocked[i], qlwi);
92                 list->insertItem(0, qlwi);
93                 list->setItemWidget(qlwi, liw);
94
95                 // Set up SIGNAL/SLOTs for this LayerItemWidget
96                 connect(liw, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
97                 connect(liw, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
98         }
99
100         int layer = (Global::numLayers - Global::activeLayer) - 1;
101         list->setCurrentRow(layer, QItemSelectionModel::SelectCurrent);
102         SetButtonStates();
103 }
104
105
106 void LayerWidget::HandleLayerSelected(int currentRow)
107 {
108         // If LayerWidget is empty, bail out
109         if (currentRow == -1)
110                 return;
111
112         // This is numbered opposite of how it's presented. In other words, the
113         // bottom of the list is 0, and items above it count upwards. So like this:
114         //
115         // (2) Layer #2
116         // (1) Layer #1
117         // (0) Background
118         //
119         // which is the opposite of the internal numbering.
120         Global::activeLayer = (Global::numLayers - currentRow) - 1;
121
122         // Set button states to sane values
123         SetButtonStates();
124 }
125
126
127 //
128 // What happens here is that for every QListWidgetItem we make, we connect it
129 // to these handlers. But we only have to worry about that when adding and
130 // moving a layer. However, when toggling states, we need to toggle the global
131 // state variables too.
132 //
133 void LayerWidget::HandleHideToggle(QListWidgetItem * qlwi, bool state)
134 {
135         int currentRow = list->row(qlwi);
136         int layer = (Global::numLayers - currentRow) - 1;
137         std::vector<bool>::iterator i = Global::layerHidden.begin() + layer;
138         (*i) = state;
139 //printf("Item #%i, new hide state is %s\n", currentRow, (state ? "ON" : "off"));
140 //printf("LayerWidget: New hide state of layer %i is %s.\n", layer, (state ? "ON" : "off"));
141         // We do this last, because otherwise the Document would get the wrong state
142         emit LayerToggled();
143 }
144
145
146 void LayerWidget::HandleLockToggle(QListWidgetItem * qlwi, bool state)
147 {
148         int currentRow = list->row(qlwi);
149         int layer = (Global::numLayers - currentRow) - 1;
150         std::vector<bool>::iterator i = Global::layerLocked.begin() + layer;
151         (*i) = state;
152 //      printf("Item #%i, new lock state is %s\n", list->row(qlwi), (state ? "ON" : "off"));
153 }
154
155
156 void LayerWidget::HandleDblClick(QListWidgetItem * /*qlwi*/)
157 {
158         EditLayer();
159 }
160
161
162 void LayerWidget::AddLayer(void)
163 {
164         // We always stick the newest layer at the top of the list (visually, the
165         // top of the list is the end, the bottom is the beginning)...
166         int count = list->count();
167         QString text = QString("Layer #%1").arg(count);
168         QListWidgetItem * qlwi = new QListWidgetItem();
169         LayerItemWidget * liw = new LayerItemWidget(text, false, false, qlwi);
170         list->insertItem(0, qlwi);
171         list->setItemWidget(qlwi, liw);
172
173         // Set up SIGNAL/SLOTs for this LayerItemWidget
174         connect(liw, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
175         connect(liw, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
176
177         SetButtonStates();
178
179         // Fix up the global state
180         Global::layerHidden.push_back(false);
181         Global::layerLocked.push_back(false);
182         Global::layerName.push_back(text.toUtf8().data());
183         Global::numLayers++;
184 }
185
186
187 void LayerWidget::DeleteLayer(void)
188 {
189         int numItems = list->count();
190
191         if (numItems == 1)
192                 return;
193
194         // N.B.: This *must* go before the item removal because that causes
195         //       HandleLayerSelected() to be fired off which causes the numbers to
196         //       be off. You have been warned!
197         // Tell the DrawingView to delete this layer in its Container:
198         emit LayerDeleted(Global::activeLayer);
199
200         int currentRow = list->currentRow();
201         QListWidgetItem * qlwi = list->currentItem();
202         list->removeItemWidget(qlwi);
203         delete qlwi;
204
205         SetButtonStates();
206
207         // Fix up the global state
208         int layer = (Global::numLayers - currentRow) - 1;
209         Global::layerHidden.erase(Global::layerHidden.begin() + layer);
210         Global::layerLocked.erase(Global::layerLocked.begin() + layer);
211         Global::layerName.erase(Global::layerName.begin() + layer);
212         Global::numLayers--;
213
214         // If we're deleting from the top of the list, we have to decrement the
215         // active layer # by 1 (since we count upward from the bottom of the list).
216         if (currentRow == 0)
217                 Global::activeLayer--;
218 }
219
220
221 void LayerWidget::EditLayer(void)
222 {
223         // Get the LayerItemWidget so we can edit it (its name, anyway)...
224         QListWidgetItem * qlwi = list->currentItem();
225         LayerItemWidget * li = (LayerItemWidget *)list->itemWidget(qlwi);
226         QString s = li->name->text();
227
228         bool ok;
229         QString result = QInputDialog::getText(this, tr("Edit Layer Name"), tr("Layer Name:"), QLineEdit::Normal, s, &ok);
230
231         if (ok && !result.isEmpty())
232         {
233                 li->name->setText(result);
234
235                 // We don't reverse the layer # here, like elsewhere, because we're
236                 // using the layer # directly instead of having to translate it from
237                 // the widget.
238                 std::vector<std::string>::iterator i = Global::layerName.begin() + Global::activeLayer;
239                 (*i) = result.toUtf8().data();
240         }
241 }
242
243
244 void LayerWidget::MoveLayerUp(void)
245 {
246         // Get information out of the LayerItemWidget (& get it from the list!)
247         int currentRow = list->currentRow();
248         QListWidgetItem * qlwi = list->currentItem();
249         LayerItemWidget * li = (LayerItemWidget *)list->itemWidget(qlwi);
250         QString s = li->name->text();
251         bool visible = li->invisible->isChecked();
252         bool editible = li->locked->isChecked();
253
254         // We have to make a new LayerItemWidget because it destroys the old one!
255         list->takeItem(currentRow);
256         list->insertItem(currentRow - 1, qlwi);
257         li = new LayerItemWidget(s, visible, editible, qlwi);
258         list->setItemWidget(qlwi, li);
259         list->setCurrentItem(qlwi);
260
261         // Set up SIGNAL/SLOTs for this LayerItemWidget
262         connect(li, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
263         connect(li, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
264
265         // Fix up the global state...
266         // N.B.: Because we handle the button states correctly, we should never
267         //       have a situation where the reference in the vector is bad.
268         int layer = (Global::numLayers - currentRow) - 1;
269         bool old = Global::layerHidden[layer];
270         Global::layerHidden[layer] = Global::layerHidden[layer + 1];
271         Global::layerHidden[layer + 1] = old;
272         old = Global::layerLocked[layer];
273         Global::layerLocked[layer] = Global::layerLocked[layer + 1];
274         Global::layerLocked[layer + 1] = old;
275         std::string oldStr = Global::layerName[layer];
276         Global::layerName[layer] = Global::layerName[layer + 1];
277         Global::layerName[layer + 1] = oldStr;
278         // We also have to tell the document to shuffle its layers too
279         emit LayersSwapped(layer, layer + 1);
280 }
281
282
283 void LayerWidget::MoveLayerDown(void)
284 {
285         // Get information out of the LayerItemWidget (& get it from the list!)
286         int currentRow = list->currentRow();
287         QListWidgetItem * qlwi = list->currentItem();
288         LayerItemWidget * li = (LayerItemWidget *)list->itemWidget(qlwi);
289         QString s = li->name->text();
290         bool visible = li->invisible->isChecked();
291         bool editible = li->locked->isChecked();
292
293         // We have to make a new LayerItemWidget because it destroys the old one!
294         list->takeItem(currentRow);
295         list->insertItem(currentRow + 1, qlwi);
296         li = new LayerItemWidget(s, visible, editible, qlwi);
297         list->setItemWidget(qlwi, li);
298         list->setCurrentItem(qlwi);
299
300         // Set up SIGNAL/SLOTs for this LayerItemWidget
301         connect(li, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
302         connect(li, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
303
304         // Fix up the global state...
305         // N.B.: Because we handle the button states correctly, we should never
306         //       have a situation where the reference in the vector is bad.
307         int layer = (Global::numLayers - currentRow) - 1;
308         bool old = Global::layerHidden[layer];
309         Global::layerHidden[layer] = Global::layerHidden[layer - 1];
310         Global::layerHidden[layer - 1] = old;
311         old = Global::layerLocked[layer];
312         Global::layerLocked[layer] = Global::layerLocked[layer - 1];
313         Global::layerLocked[layer - 1] = old;
314         std::string oldStr = Global::layerName[layer];
315         Global::layerName[layer] = Global::layerName[layer - 1];
316         Global::layerName[layer - 1] = oldStr;
317         // We also have to tell the document to shuffle its layers too
318         emit LayersSwapped(layer, layer - 1);
319 }
320
321
322 //
323 // Set button states in this widget to sane values
324 //
325 void LayerWidget::SetButtonStates(void)
326 {
327         int numItems = list->count();
328         int currentRow = list->currentRow();
329
330         layerDown->setEnabled(currentRow == (numItems - 1) ? false : true);
331         layerUp->setEnabled(currentRow == 0 ? false : true);
332         removeLayer->setEnabled(numItems == 1 ? false : true);
333 }
334