Developer Documentation
postProcessorWidget.cc
1/*===========================================================================*\
2* *
3* OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39* *
40\*===========================================================================*/
41
42
43
45#include <OpenFlipper/common/RendererInfo.hh>
47
48#include <QtWidgets>
49
50#include "postProcessorWidget.hh"
51
52
53PostProcessorDialog::PostProcessorDialog(QWidget *_parent)
54 : QDialog(_parent)
55{
56 setupUi(this);
57
58 list->setContextMenuPolicy(Qt::CustomContextMenu);
59 activeList->setContextMenuPolicy(Qt::CustomContextMenu);
60
61 connect(closeButton, SIGNAL(clicked()), this, SLOT(accept()));
62 connect(list,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(slotContextMenuActivate(const QPoint&)));
63 connect(activeList,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(slotContextMenuDeactivate(const QPoint&)));
64 connect(activateButton,SIGNAL(clicked()),this,SLOT(slotActivatePostProcessor()));
65 connect(deactivateButton,SIGNAL(clicked()),this,SLOT(slotDeactivatePostProcessor()));
66 connect(upButton,SIGNAL(clicked()),this,SLOT(slotMoveUp()));
67 connect(downButton,SIGNAL(clicked()),this,SLOT(slotMoveDown()));
68 connect(saveButton,SIGNAL(clicked()),this,SLOT(slotSaveActive()));
69 connect(refreshButton,SIGNAL(clicked()), this,SLOT(refresh()));
70
71 //set icons
72 QString iconPath = OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator();
73
74 closeButton->setIcon( QIcon(iconPath + "window-close.png"));
75 saveButton->setIcon( QIcon(iconPath + "document-save.png"));
76 refreshButton->setIcon( QIcon(iconPath + "edit-redo.png"));
77
78}
79
80void PostProcessorDialog::closeEvent(QCloseEvent *_event)
81{
82 _event->accept();
83 accept();
84}
85
86void PostProcessorDialog::showEvent ( QShowEvent * )
87{
88 initWindow();
89}
90
92{
94 list->clear();
95 activeList->clear();
96 activeRowToRow_.clear();
97
98 //first, fill already activated processors in the right order
99 for (int i = 0; i < postProcessorManager().numActive(currentExaminer_); ++i)
100 {
101 unsigned int id = postProcessorManager().activeId(currentExaminer_, i);
102 activeRowToRow_.push_back(id);
103
104 QListWidgetItem *activeItem = new QListWidgetItem("");
105 activeList->addItem(activeItem);
106 QFrame* frame = createFrame(*postProcessorManager()[id]);
107 activeItem->setSizeHint(frame->sizeHint());
108 activeList->setItemWidget(activeItem,frame);
109 }
110
111 //list all available post processors (hidden, if active)
112 for ( unsigned int i = 0 ; i < postProcessorManager().available() ; ++i)
113 {
114
115 // Get and check post processor
116 PostProcessorInfo* processor = postProcessorManager()[i];
117 if ( ! processor )
118 continue;
119
120 QFrame* frame = createFrame(*processor);
121
122 QListWidgetItem *item = new QListWidgetItem("");
123 item->setSizeHint( frame->sizeHint() );
124
125 list->addItem(item);
126
127 list->setItemWidget(item, frame);
128
129 //is the postProcess active? if so, hide it
130 bool found = false;
131 for (std::vector<unsigned>::iterator iter = activeRowToRow_.begin(); iter != activeRowToRow_.end() && !found; ++iter)
132 found = (*iter == i);
133 if ( found )
134 list->setRowHidden(list->row(item),true);
135 }
136
137}
138
140{
141 QList<QListWidgetItem*> selectedItems = list->selectedItems();
142
143 for (int i=0; i < selectedItems.size(); ++i)
144 {
145 QListWidgetItem* item = selectedItems[i];
146 const int currentRow = list->row( item );
147
148 postProcessorManager().append( currentRow, currentExaminer_);
149
150 //disable in aviable list
151 item->setHidden(true);
152 item->setSelected(false);
153
154 //add to active list
155 QListWidgetItem *activeItem = new QListWidgetItem("");
156 activeList->addItem(activeItem);
157 activeItem->setSelected(true);
158
159 QFrame* frame = createFrame(*postProcessorManager()[currentRow]);
160 activeItem->setSizeHint( frame->sizeHint() );
161 activeList->setItemWidget(activeItem,frame);
162 activeRowToRow_.push_back(currentRow);
163 }
164
166
167}
168
170{
171 QList<QListWidgetItem*> selectedItems = activeList->selectedItems();
172
173 for (int i=0; i < selectedItems.size(); ++i)
174 {
175 QListWidgetItem* activeItem = selectedItems[i];
176
177 const unsigned chainPos = activeList->row(activeItem);
178 const unsigned activeID = activeRowToRow_[chainPos];
179 QListWidgetItem* item = list->item(activeID);
180
181 //remove postprocessor
182 postProcessorManager().remove(currentExaminer_, chainPos);
183
184 //enable in aviable list
185 item->setHidden(false);
186 item->setSelected(true);
187
188 //remove from active list
189 //update active row ids
190 for (unsigned j = chainPos; j < activeRowToRow_.size()-1; ++j)
192
193 //from qt doc: Items removed from a list widget will not be managed by Qt, and will need to be deleted manually.
194 activeItem = activeList->takeItem(activeList->row(activeItem));
195 delete activeItem;
196 }
197 activeRowToRow_.erase( activeRowToRow_.end()-selectedItems.size(), activeRowToRow_.end());
198
200}
201
202void PostProcessorDialog::slotMovePostProcessor(unsigned _from,unsigned _to)
203{
204
205 if (_from >= static_cast<unsigned>(activeList->count()))
206 return;
207
208 if (_to >= static_cast<unsigned>(activeList->count()))
209 _to = activeList->count()-1;
210
211 if (_from == _to)
212 return;
213
214 //swap widget
215 QListWidgetItem* activeItem = activeList->takeItem(_from);
216 activeList->insertItem(_to,activeItem);
217 QFrame* frame = createFrame(*postProcessorManager()[activeRowToRow_[_from]]);
218 activeItem->setSizeHint(frame->sizeHint());
219 activeList->setItemWidget(activeItem,frame);
220 activeItem->setSelected(true);
221
222 //swap postprocessor
223 const int chainPos = _from;
224 const int activeID = activeRowToRow_[_from];
225 postProcessorManager().remove(currentExaminer_, chainPos);
226 postProcessorManager().insert(activeID,_to,currentExaminer_);
227
228 //swap active ID to current chain position map
229 int inc = (_from > _to)? -1: +1;
230 for(unsigned int currentRow = _from;currentRow != _to; currentRow += inc)
231 std::swap(activeRowToRow_[currentRow+inc],activeRowToRow_[currentRow]);
232
234}
235
236
238{
239 if (!list->count())
240 return;
241
242 QMenu *menu = new QMenu(list);
243 QAction* action = 0;
244
245 action = menu->addAction(tr("Activate"));
246 connect(action,SIGNAL(triggered(bool)),this,SLOT(slotActivatePostProcessor()));
247
248 menu->exec(list->mapToGlobal(_point),0);
249
250}
251
253{
254 if (!activeList->count())
255 return;
256
257 QMenu *menu = new QMenu(activeList);
258 QAction* action = 0;
259
260 action = menu->addAction(tr("Up"));
261 connect(action,SIGNAL(triggered(bool)),this,SLOT(slotMoveUp()));
262 action = menu->addAction(tr("Down"));
263 connect(action,SIGNAL(triggered(bool)),this,SLOT(slotMoveDown()));
264 action = menu->addAction(tr("Deactivate"));
265 connect(action,SIGNAL(triggered(bool)),this,SLOT(slotDeactivatePostProcessor()));
266
267 menu->exec(activeList->mapToGlobal(_point),0);
268
269}
270
271QFrame* PostProcessorDialog::createFrame(const PostProcessorInfo& _pPI)
272{
273 QFrame* frame = new QFrame();
274 QHBoxLayout* hlayout = new QHBoxLayout;
275
276 QLabel* name = new QLabel( _pPI.name );
277 QFont font;
278 font.setBold(true);
279 font.setPointSize(10);
280 name->setFont(font);
281 QLabel* version = new QLabel( _pPI.version );
282 QPushButton* optionsButton = new QPushButton("Options");
283 hlayout->addWidget(name);
284 hlayout->addStretch();
285 hlayout->addWidget(version);
286
287 optionsButton->setEnabled(false);
288 if (_pPI.optionsAction != 0)
289 {
290 optionsButton->setEnabled(true);
291 connect(optionsButton,SIGNAL(clicked()),_pPI.optionsAction,SLOT(trigger()));
292 }
293
294 QVBoxLayout* vlayout = new QVBoxLayout;
295
296 QLabel* description = new QLabel( _pPI.description );
297
298 vlayout->addLayout(hlayout,20);
299
300 QHBoxLayout* optionsLayout = new QHBoxLayout();
301 vlayout->addLayout(optionsLayout);
302 optionsLayout->addWidget(description);
303 optionsLayout->addStretch();
304 optionsLayout->addWidget(optionsButton);
305
306 frame->setLayout(vlayout);
307 frame->adjustSize();
308
309 return frame;
310}
311
312
313
314template<typename TCmp>
316{
317 QListWidget* list_;
318public:
319 explicit QListWidgetRowCmp(QListWidget* _list):list_(_list){}
320 bool operator()(QListWidgetItem* left, QListWidgetItem* right)
321 {
322 return TCmp()(list_->row(left) , list_->row(right));
323 }
324};
325
327{
328 int start = 0;
329 QList<QListWidgetItem*> selectedItems = activeList->selectedItems();
330
331 //sort list, so the top is the last element
332 std::sort(selectedItems.begin(), selectedItems.end(), QListWidgetRowCmp<std::greater<int> >(activeList));
333
334 //dont move the last one
335 //if the last one wasnt moved, dont move the direct followers
336 for(int i=0; i < selectedItems.size() && activeList->row(selectedItems[i]) == activeList->count()-1-i;++i)
337 --start;
338
339 //move bottom first
340 for (int i=selectedItems.size()-1+start; i >= 0 ; --i)
341 {
342 QListWidgetItem* activeItem = activeList->selectedItems()[i];
343 unsigned selectedRow = activeList->row(activeItem);
344 slotMovePostProcessor(selectedRow,selectedRow+1);
345 }
346}
347
348
350{
351 int start = 0;
352 QList<QListWidgetItem*> selectedItems = activeList->selectedItems();
353
354 //sort list, so the top is the first element
355 std::sort(selectedItems.begin(), selectedItems.end(), QListWidgetRowCmp<std::less<int> >(activeList));
356
357 //dont move the first one
358 //if the first one wasnt moved, dont move the direct followers
359 for(int i=0; i < selectedItems.size() && activeList->row(selectedItems[i]) == i;++i)
360 ++start;
361
362 //move top first
363 for (int i=start; i < selectedItems.size(); ++i)
364 {
365 QListWidgetItem* activeItem = selectedItems[i];
366 unsigned selectedRow = activeList->row(activeItem);
367 slotMovePostProcessor(selectedRow,selectedRow-1);
368 }
369}
370
372{
373 QStringList activeList("");
374
375 for (int i = 0; i < postProcessorManager().numActive(currentExaminer_); ++i)
376 {
377 unsigned int id = postProcessorManager().activeId(currentExaminer_, i);
378 activeList.push_back(postProcessorManager()[id]->name);
379 }
380
381 OpenFlipperSettings().setValue(QString("PostProcessor/Viewer/%1").arg(currentExaminer_),activeList);
382}
383
384QStringList PostProcessorDialog::getSavedPostProcessorNames(const unsigned _examiner)
385{
386 return OpenFlipperSettings().value(QString("PostProcessor/Viewer/%1").arg(_examiner),QStringList("")).toStringList();
387}
388
390{
391 QStringList active = getSavedPostProcessorNames(_examiner);
392 for (QStringList::iterator iter = active.begin(); iter != active.end(); ++iter)
393 {
394 postProcessorManager().append(*iter,_examiner);
395 }
396}
397
399{
400 initWindow();
401}
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
void initWindow()
initiaize the window with the post processors of the current examiner
static void loadSavedPostProcessors(const unsigned _examiner)
append all saved post processors
std::vector< unsigned > activeRowToRow_
maps activeRow from activeList (same as chainIdx from RendererInfo) to row from list (same as activeI...
static QStringList getSavedPostProcessorNames(const unsigned _examiner)
return the names of all saved post processors
void slotMoveUp()
move the selected active postprocessor 1 up
void slotDeactivatePostProcessor()
Deactivates the current postProcessor.
void slotContextMenuActivate(const QPoint &_point)
Show the custom context menu for activation.
void slotMovePostProcessor(unsigned _from, unsigned _to)
Move the position/ordering of postprocessor in the postprocessor.
void updateExaminer(unsigned _viewer)
request an update for an specified viewer
unsigned currentExaminer_
holds the examiner id for the window
void slotSaveActive()
saves active post processor chain
void refresh()
refreshes the content of the dialog with current examiner
void slotActivatePostProcessor()
Activates the post processor (triggered via the context menu)
void slotMoveDown()
move the selected active postprocessor 1 down
void slotContextMenuDeactivate(const QPoint &_point)
Show the custom context menu for deactivation.
QAction * optionsAction
Possible action to add an options action or menu to the system.
QString name
Name of the plugin ( requested from the plugin on load)
QString version
Version of the plugin.
QString description
Description of the plugin.
unsigned int activeId(int _id, int _chainIdx=0)
Get the id of the active post processor for viewer at chain index.
size_t available()
number of available post processor
int numActive(int _id)
Get the number of active post processors for viewer.
void append(unsigned int _active, int _viewerId)
Append the active post processor to the chain for viewer.
void remove(int _id, int _chainIdx)
Remove a post processor at the specified chain index.
void insert(unsigned int _active, int _chainIdx, int _viewerId)
Insert the active post processor to the chain for viewer.
unsigned int activeExaminer()
Get the id of the examiner which got the last mouse events.