1 /***************************************************************************
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 3 of the License, or *
6 * (at your option) any later version. *
7 * *
8 ***************************************************************************/
9
10 #include "TabFrame.h"
11
12 #include "FlowLayout.h"
13 #include "TabButton.h"
14 #include "WulforUtil.h"
15 #include "ArenaWidgetManager.h"
16 #include "DebugHelper.h"
17 #include "GlobalTimer.h"
18
19 #if QT_VERSION >= 0x050000
20 #include <QtWidgets>
21 #else
22 #include <QtGui>
23 #endif
24
25 #include <QPushButton>
26 #include <QWheelEvent>
27 #include <functional>
28
TabFrame(QWidget * parent)29 TabFrame::TabFrame(QWidget *parent) :
30 QFrame(parent)
31 {
32 DEBUG_BLOCK
33
34 setAcceptDrops(true);
35
36 fr_layout = new FlowLayout(this);
37 fr_layout->setContentsMargins(0, 0, 0, 0);
38
39 setMinimumHeight(20);
40 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
41
42 shortcuts << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_1), this))
43 << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_2), this))
44 << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_3), this))
45 << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_4), this))
46 << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_5), this))
47 << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_6), this))
48 << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_7), this))
49 << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_8), this))
50 << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_9), this))
51 << (new QShortcut(QKeySequence(Qt::ALT + Qt::Key_0), this));
52
53 for (const auto &s : shortcuts){
54 s->setContext(Qt::ApplicationShortcut);
55
56 connect(s, SIGNAL(activated()), this, SLOT(slotShorcuts()));
57 }
58
59 connect(GlobalTimer::getInstance(), SIGNAL(second()), this, SLOT(redraw()));
60 }
61
62
~TabFrame()63 TabFrame::~TabFrame(){
64 DEBUG_BLOCK
65
66 auto it = tbtn_map.begin();
67
68 for (; it != tbtn_map.end(); ++it){
69 TabButton *btn = const_cast<TabButton*>(it.key());
70
71 btn->deleteLater();
72 }
73 }
74
resizeEvent(QResizeEvent * e)75 void TabFrame::resizeEvent(QResizeEvent *e){
76 e->accept();
77
78 QFrame::updateGeometry();
79 }
80
eventFilter(QObject * obj,QEvent * e)81 bool TabFrame::eventFilter(QObject *obj, QEvent *e){
82 TabButton *btn = qobject_cast<TabButton*>(obj);
83 QWheelEvent *w_e = reinterpret_cast<QWheelEvent*>(e);
84
85 if (btn && (e->type() == QEvent::Wheel) && w_e){
86 int numDegrees = (w_e->delta() < 0)? (-1*w_e->delta()/8) : (w_e->delta()/8);
87 int numSteps = numDegrees/15;
88 std::function<void()> f = [this]() { this->nextTab(); };
89
90 if (w_e->delta() < 0)
91 f = [this]() { this->prevTab(); };
92
93 for (int i = 0; i < numSteps; i++)
94 f();
95
96 return true;
97 }
98
99 return QFrame::eventFilter(obj, e);
100 }
101
sizeHint() const102 QSize TabFrame::sizeHint() const {
103 QSize s(fr_layout->sizeHint().width() , fr_layout->heightForWidth(width()));
104 return s;
105 }
106
minimumSizeHint() const107 QSize TabFrame::minimumSizeHint() const{
108 return sizeHint();
109 }
110
removeWidget(ArenaWidget * awgt)111 void TabFrame::removeWidget(ArenaWidget *awgt){
112 DEBUG_BLOCK
113
114 if (!awgt_map.contains(awgt))
115 return;
116
117 TabButton *btn = const_cast<TabButton*>(awgt_map.value(awgt));
118
119 fr_layout->removeWidget(btn);
120 tbtn_map.remove(btn);
121 awgt_map.remove(awgt);
122
123 btn->deleteLater();
124
125 historyPurge(awgt);
126 historyPop();
127
128 if (awgt->toolButton())
129 awgt->toolButton()->setChecked(false);
130 }
131
insertWidget(ArenaWidget * awgt)132 void TabFrame::insertWidget(ArenaWidget *awgt){
133 DEBUG_BLOCK
134
135 if (awgt_map.contains(awgt) || (awgt && (awgt->state() & ArenaWidget::Hidden)) || !awgt)
136 return;
137
138 TabButton *btn = new TabButton();
139 btn->setText(awgt->getArenaShortTitle().left(32));
140 btn->setToolTip(WulforUtil::getInstance()->compactToolTipText(awgt->getArenaTitle(), 60, "\n"));
141 btn->setWidgetIcon(awgt->getPixmap());
142 btn->setContextMenuPolicy(Qt::CustomContextMenu);
143 btn->installEventFilter(this);
144
145 fr_layout->addWidget(btn);
146
147 awgt_map.insert(awgt, btn);
148 tbtn_map.insert(btn, awgt);
149
150 if (awgt->toolButton())
151 awgt->toolButton()->setChecked(true);
152
153 connect(btn, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenu()));
154 connect(btn, SIGNAL(clicked()), this, SLOT(buttonClicked()));
155 connect(btn, SIGNAL(closeRequest()), this, SLOT(closeRequsted()));
156 connect(btn, SIGNAL(dropped(TabButton*)), this, SLOT(slotDropped(TabButton*)));
157 }
158
hasWidget(ArenaWidget * awgt) const159 bool TabFrame::hasWidget(ArenaWidget *awgt) const{
160 DEBUG_BLOCK
161
162 return awgt_map.contains(awgt);
163 }
164
mapped(ArenaWidget * awgt)165 void TabFrame::mapped(ArenaWidget *awgt){
166 DEBUG_BLOCK
167
168 if (!awgt_map.contains(awgt))
169 return;
170
171 TabButton *btn = const_cast<TabButton*>(awgt_map.value(awgt));
172
173 btn->setChecked(true);
174 btn->setFocus();
175
176 historyPush(awgt);
177 }
178
updated(ArenaWidget * awgt)179 void TabFrame::updated ( ArenaWidget* awgt ) {
180 DEBUG_BLOCK
181
182 if (awgt->state() & ArenaWidget::Hidden){
183 removeWidget(awgt);
184 }
185 else if (!awgt_map.contains(awgt)){
186 insertWidget(awgt);
187 }
188 }
189
redraw()190 void TabFrame::redraw() {
191 DEBUG_BLOCK
192
193 auto it = tbtn_map.begin();
194
195 for (; it != tbtn_map.end(); ++it){
196 TabButton *btn = const_cast<TabButton*>(it.key());
197 ArenaWidget *awgt = const_cast<ArenaWidget*>(it.value());
198
199 btn->setText(awgt->getArenaShortTitle().left(32));
200 btn->setToolTip(WulforUtil::getInstance()->compactToolTipText(awgt->getArenaTitle(), 60, "\n"));
201 btn->setWidgetIcon(awgt->getPixmap());
202
203 if (awgt->state() & ArenaWidget::Hidden)
204 continue;
205 else
206 btn->resetGeometry();
207 }
208 }
209
historyPush(ArenaWidget * awgt)210 void TabFrame::historyPush(ArenaWidget *awgt){
211 DEBUG_BLOCK
212
213 historyPurge(awgt);
214
215 history.push_back(awgt);
216 }
217
historyPurge(ArenaWidget * awgt)218 void TabFrame::historyPurge(ArenaWidget *awgt){
219 DEBUG_BLOCK
220
221 if (history.contains(awgt))
222 history.removeAt(history.indexOf(awgt));
223 }
224
historyPop()225 void TabFrame::historyPop(){
226 DEBUG_BLOCK
227
228 if (history.isEmpty() && fr_layout->count() > 0){
229 QLayoutItem *item = fr_layout->itemAt(0);
230
231 if (!item)
232 return;
233
234 TabButton *btn = qobject_cast<TabButton*>(item->widget());
235
236 if (btn)
237 ArenaWidgetManager::getInstance()->activate(tbtn_map[btn]);
238
239 return;
240 }
241 else if (history.isEmpty()){
242 ArenaWidgetManager::getInstance()->activate(NULL);
243
244 return;
245 }
246
247 ArenaWidget *awgt = history.takeLast();
248
249 ArenaWidgetManager::getInstance()->activate(awgt);
250 }
251
buttonClicked()252 void TabFrame::buttonClicked(){
253 DEBUG_BLOCK
254
255 TabButton *btn = qobject_cast<TabButton*>(sender());
256
257 if (!(btn && tbtn_map.contains(btn)))
258 return;
259
260 btn->setFocus();
261
262 ArenaWidgetManager::getInstance()->activate(tbtn_map[btn]);
263 }
264
closeRequsted()265 void TabFrame::closeRequsted() {
266 DEBUG_BLOCK
267
268 TabButton *btn = qobject_cast<TabButton*>(sender());
269
270 if (!(btn && tbtn_map.contains(btn)))
271 return;
272
273 ArenaWidget *awgt = const_cast<ArenaWidget*>(tbtn_map[btn]);
274 ArenaWidgetManager::getInstance()->rem(awgt);
275 }
276
nextTab()277 void TabFrame::nextTab(){
278 DEBUG_BLOCK
279
280 TabButton *next = NULL;
281
282 for (int i = 0; i < fr_layout->count(); i++){
283 TabButton *t = qobject_cast<TabButton*>(fr_layout->itemAt(i)->widget());
284
285 if (t && t->isChecked()){
286 if (i == (fr_layout->count()-1)){
287 next = qobject_cast<TabButton*>(fr_layout->itemAt(0)->widget());
288 break;
289 }
290
291 next = qobject_cast<TabButton*>(fr_layout->itemAt(i+1)->widget());
292 break;
293 }
294 }
295
296 if (!next)
297 return;
298
299 ArenaWidgetManager::getInstance()->activate(tbtn_map[next]);
300 }
301
prevTab()302 void TabFrame::prevTab(){
303 DEBUG_BLOCK
304
305 TabButton *next = NULL;
306
307 for (int i = 0; i < fr_layout->count(); i++){
308 TabButton *t = qobject_cast<TabButton*>(fr_layout->itemAt(i)->widget());
309
310 if (t && t->isChecked()){
311 if (!i){
312 next = qobject_cast<TabButton*>(fr_layout->itemAt(fr_layout->count()-1)->widget());
313 break;
314 }
315
316 next = qobject_cast<TabButton*>(fr_layout->itemAt(i-1)->widget());
317 break;
318 }
319 }
320
321 if (!next)
322 return;
323
324 ArenaWidgetManager::getInstance()->activate(tbtn_map[next]);
325 }
326
slotShorcuts()327 void TabFrame::slotShorcuts(){
328 DEBUG_BLOCK
329
330 QShortcut *sh = qobject_cast<QShortcut*>(sender());
331
332 if (!sh)
333 return;
334
335 int index = shortcuts.indexOf(sh);
336
337 if (index >= 0 && fr_layout->count() >= (index + 1)){
338 TabButton *next = qobject_cast<TabButton*>(fr_layout->itemAt(index)->widget());
339
340 if (!next)
341 return;
342
343 ArenaWidgetManager::getInstance()->activate(tbtn_map[next]);
344 }
345 }
346
slotContextMenu()347 void TabFrame::slotContextMenu() {
348 DEBUG_BLOCK
349
350 TabButton *btn = qobject_cast<TabButton*>(sender());
351
352 if (!(btn && tbtn_map.contains(btn)))
353 return;
354
355 ArenaWidget *awgt = const_cast<ArenaWidget*>(tbtn_map[btn]);
356
357 if (awgt) {
358 QMenu *widget_menu = awgt->getMenu();
359 if (widget_menu) {
360 widget_menu->exec(btn->mapToGlobal(btn->rect().bottomLeft()));
361 } else {
362 widget_menu = new QMenu(this);
363 widget_menu->addAction(WulforUtil::getInstance()->getPixmap(WulforUtil::eiEDITDELETE), tr("Close"));
364
365 if (widget_menu->exec(QCursor::pos()))
366 ArenaWidgetManager::getInstance()->rem(awgt);
367
368 delete widget_menu;
369 }
370 }
371 }
372
slotDropped(TabButton * dropped)373 void TabFrame::slotDropped(TabButton *dropped){
374 DEBUG_BLOCK
375
376 TabButton *on = qobject_cast<TabButton*>(sender());
377
378 if (!(on && dropped && on != dropped))
379 return;
380
381 fr_layout->place(on, dropped);
382 }
383
moveLeft()384 void TabFrame::moveLeft(){
385 DEBUG_BLOCK
386
387 for (int i = 0; i < fr_layout->count(); i++){
388 QLayoutItem *item = const_cast<QLayoutItem*>(fr_layout->itemAt(i));
389 TabButton *t = qobject_cast<TabButton*>(item->widget());
390
391 if (t && t->isChecked()){
392 fr_layout->moveLeft(item);
393
394 break;
395 }
396 }
397 }
398
moveRight()399 void TabFrame::moveRight(){
400 DEBUG_BLOCK
401
402 for (int i = 0; i < fr_layout->count(); i++){
403 QLayoutItem *item = const_cast<QLayoutItem*>(fr_layout->itemAt(i));
404 TabButton *t = qobject_cast<TabButton*>(item->widget());
405
406 if (t && t->isChecked()){
407 fr_layout->moveRight(item);
408
409 break;
410 }
411 }
412 }
413
toggled(ArenaWidget * awgt)414 void TabFrame::toggled ( ArenaWidget* awgt ) {
415 DEBUG_BLOCK
416
417 if (!awgt)
418 return;
419
420 if (!(awgt->state() & ArenaWidget::Singleton))
421 return;
422
423 if (awgt->state() & ArenaWidget::Hidden)
424 ArenaWidgetManager::getInstance()->activate(awgt);
425 else
426 ArenaWidgetManager::getInstance()->rem(awgt);
427 }
428
429