2 // layerwidget.cpp: Layer add/remove/use widget
4 // Part of the Architektonas Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
8 // JLH = James Hammons <jlhamm@acm.org>
11 // --- ---------- ------------------------------------------------------------
12 // JLH 07/11/2013 Created this file
15 #include "layerwidget.h"
17 #include "layeritemwidget.h"
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)
24 QListWidgetItem * qlwi = new QListWidgetItem(list);
25 LayerItemWidget * liw = new LayerItemWidget("Background", false, false, qlwi);
26 list->setItemWidget(qlwi, liw);
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"));
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"));
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);
48 QVBoxLayout * mainLayout = new QVBoxLayout;
49 mainLayout->addWidget(list);
50 mainLayout->addLayout(hbox1);
52 setLayout(mainLayout);
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()));
62 connect(liw, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
63 connect(liw, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
65 list->setCurrentRow(0);
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");
78 LayerWidget::~LayerWidget()
82 void LayerWidget::Reload(void)
86 for(int i=0; i<Global::numLayers; i++)
88 QListWidgetItem * qlwi = new QListWidgetItem();
89 LayerItemWidget * liw = new LayerItemWidget(Global::layerName[i].c_str(), Global::layerHidden[i], Global::layerLocked[i], qlwi);
90 list->insertItem(0, qlwi);
91 list->setItemWidget(qlwi, liw);
93 // Set up SIGNAL/SLOTs for this LayerItemWidget
94 connect(liw, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
95 connect(liw, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
98 int layer = (Global::numLayers - Global::activeLayer) - 1;
99 list->setCurrentRow(layer, QItemSelectionModel::SelectCurrent);
103 void LayerWidget::HandleLayerSelected(int currentRow)
105 // If LayerWidget is empty, bail out
106 if (currentRow == -1)
109 // This is numbered opposite of how it's presented. In other words, the
110 // bottom of the list is 0, and items above it count upwards. So like this:
116 // which is the opposite of the internal numbering.
117 Global::activeLayer = (Global::numLayers - currentRow) - 1;
119 // Set button states to sane values
124 // What happens here is that for every QListWidgetItem we make, we connect it
125 // to these handlers. But we only have to worry about that when adding and
126 // moving a layer. However, when toggling states, we need to toggle the global
127 // state variables too.
129 void LayerWidget::HandleHideToggle(QListWidgetItem * qlwi, bool state)
131 int currentRow = list->row(qlwi);
132 int layer = (Global::numLayers - currentRow) - 1;
133 std::vector<bool>::iterator i = Global::layerHidden.begin() + layer;
135 //printf("Item #%i, new hide state is %s\n", currentRow, (state ? "ON" : "off"));
136 //printf("LayerWidget: New hide state of layer %i is %s.\n", layer, (state ? "ON" : "off"));
137 // We do this last, because otherwise the Document would get the wrong state
141 void LayerWidget::HandleLockToggle(QListWidgetItem * qlwi, bool state)
143 int currentRow = list->row(qlwi);
144 int layer = (Global::numLayers - currentRow) - 1;
145 std::vector<bool>::iterator i = Global::layerLocked.begin() + layer;
147 // printf("Item #%i, new lock state is %s\n", list->row(qlwi), (state ? "ON" : "off"));
150 void LayerWidget::HandleDblClick(QListWidgetItem * /*qlwi*/)
155 void LayerWidget::AddLayer(void)
157 // We always stick the newest layer at the top of the list (visually, the
158 // top of the list is the end, the bottom is the beginning)...
159 int count = list->count();
160 QString text = QString("Layer #%1").arg(count);
161 QListWidgetItem * qlwi = new QListWidgetItem();
162 LayerItemWidget * liw = new LayerItemWidget(text, false, false, qlwi);
163 list->insertItem(0, qlwi);
164 list->setItemWidget(qlwi, liw);
166 // Set up SIGNAL/SLOTs for this LayerItemWidget
167 connect(liw, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
168 connect(liw, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
172 // Fix up the global state
173 Global::layerHidden.push_back(false);
174 Global::layerLocked.push_back(false);
175 Global::layerName.push_back(text.toUtf8().data());
179 void LayerWidget::DeleteLayer(void)
181 int numItems = list->count();
186 // N.B.: This *must* go before the item removal because that causes
187 // HandleLayerSelected() to be fired off which causes the numbers to
188 // be off. You have been warned!
189 // Tell the DrawingView to delete this layer in its Container:
190 emit LayerDeleted(Global::activeLayer);
192 int currentRow = list->currentRow();
193 QListWidgetItem * qlwi = list->currentItem();
194 list->removeItemWidget(qlwi);
199 // Fix up the global state
200 int layer = (Global::numLayers - currentRow) - 1;
201 Global::layerHidden.erase(Global::layerHidden.begin() + layer);
202 Global::layerLocked.erase(Global::layerLocked.begin() + layer);
203 Global::layerName.erase(Global::layerName.begin() + layer);
206 // If we're deleting from the top of the list, we have to decrement the
207 // active layer # by 1 (since we count upward from the bottom of the list).
209 Global::activeLayer--;
212 void LayerWidget::EditLayer(void)
214 // Get the LayerItemWidget so we can edit it (its name, anyway)...
215 QListWidgetItem * qlwi = list->currentItem();
216 LayerItemWidget * li = (LayerItemWidget *)list->itemWidget(qlwi);
217 QString s = li->name->text();
220 QString result = QInputDialog::getText(this, tr("Edit Layer Name"), tr("Layer Name:"), QLineEdit::Normal, s, &ok);
222 if (ok && !result.isEmpty())
224 li->name->setText(result);
226 // We don't reverse the layer # here, like elsewhere, because we're
227 // using the layer # directly instead of having to translate it from
229 std::vector<std::string>::iterator i = Global::layerName.begin() + Global::activeLayer;
230 (*i) = result.toUtf8().data();
234 void LayerWidget::MoveLayerUp(void)
236 // Get information out of the LayerItemWidget (& get it from the list!)
237 int currentRow = list->currentRow();
238 QListWidgetItem * qlwi = list->currentItem();
239 LayerItemWidget * li = (LayerItemWidget *)list->itemWidget(qlwi);
240 QString s = li->name->text();
241 bool visible = li->invisible->isChecked();
242 bool editible = li->locked->isChecked();
244 // We have to make a new LayerItemWidget because it destroys the old one!
245 list->takeItem(currentRow);
246 list->insertItem(currentRow - 1, qlwi);
247 li = new LayerItemWidget(s, visible, editible, qlwi);
248 list->setItemWidget(qlwi, li);
249 list->setCurrentItem(qlwi);
251 // Set up SIGNAL/SLOTs for this LayerItemWidget
252 connect(li, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
253 connect(li, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
255 // Fix up the global state...
256 // N.B.: Because we handle the button states correctly, we should never
257 // have a situation where the reference in the vector is bad.
258 int layer = (Global::numLayers - currentRow) - 1;
259 bool old = Global::layerHidden[layer];
260 Global::layerHidden[layer] = Global::layerHidden[layer + 1];
261 Global::layerHidden[layer + 1] = old;
262 old = Global::layerLocked[layer];
263 Global::layerLocked[layer] = Global::layerLocked[layer + 1];
264 Global::layerLocked[layer + 1] = old;
265 std::string oldStr = Global::layerName[layer];
266 Global::layerName[layer] = Global::layerName[layer + 1];
267 Global::layerName[layer + 1] = oldStr;
268 // We also have to tell the document to shuffle its layers too
269 emit LayersSwapped(layer, layer + 1);
272 void LayerWidget::MoveLayerDown(void)
274 // Get information out of the LayerItemWidget (& get it from the list!)
275 int currentRow = list->currentRow();
276 QListWidgetItem * qlwi = list->currentItem();
277 LayerItemWidget * li = (LayerItemWidget *)list->itemWidget(qlwi);
278 QString s = li->name->text();
279 bool visible = li->invisible->isChecked();
280 bool editible = li->locked->isChecked();
282 // We have to make a new LayerItemWidget because it destroys the old one!
283 list->takeItem(currentRow);
284 list->insertItem(currentRow + 1, qlwi);
285 li = new LayerItemWidget(s, visible, editible, qlwi);
286 list->setItemWidget(qlwi, li);
287 list->setCurrentItem(qlwi);
289 // Set up SIGNAL/SLOTs for this LayerItemWidget
290 connect(li, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
291 connect(li, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
293 // Fix up the global state...
294 // N.B.: Because we handle the button states correctly, we should never
295 // have a situation where the reference in the vector is bad.
296 int layer = (Global::numLayers - currentRow) - 1;
297 bool old = Global::layerHidden[layer];
298 Global::layerHidden[layer] = Global::layerHidden[layer - 1];
299 Global::layerHidden[layer - 1] = old;
300 old = Global::layerLocked[layer];
301 Global::layerLocked[layer] = Global::layerLocked[layer - 1];
302 Global::layerLocked[layer - 1] = old;
303 std::string oldStr = Global::layerName[layer];
304 Global::layerName[layer] = Global::layerName[layer - 1];
305 Global::layerName[layer - 1] = oldStr;
306 // We also have to tell the document to shuffle its layers too
307 emit LayersSwapped(layer, layer - 1);
311 // Set button states in this widget to sane values
313 void LayerWidget::SetButtonStates(void)
315 int numItems = list->count();
316 int currentRow = list->currentRow();
318 layerDown->setEnabled(currentRow == (numItems - 1) ? false : true);
319 layerUp->setEnabled(currentRow == 0 ? false : true);
320 removeLayer->setEnabled(numItems == 1 ? false : true);