dtkWidgetsMenuBar.cpp 29.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Version: $Id$
//
//

// Commentary:
//
//

// Change Log:
//
//

// Code:

Julien Wintz's avatar
Julien Wintz committed
15
#include "dtkWidgetsMenuBar.h"
Julien Wintz's avatar
Julien Wintz committed
16
#include "dtkWidgetsMenuBar_p.h"
17
18
#include "dtkWidgetsMenu+ux.h"
#include "dtkWidgetsMenu.h"
Julien Wintz's avatar
Julien Wintz committed
19
#include "dtkWidgetsMenuBar_p.h"
Julien Wintz's avatar
Julien Wintz committed
20
#include "dtkWidgetsMenuSpy.h"
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
21
#include "dtkWidgetsOverlayPane.h"
SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
22
#include "dtkWidgetsOverlayPaneSlider.h"
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
23

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
24
#include <dtkFonts/dtkFontAwesome>
25

26
#include <dtkThemes/dtkThemesEngine>
27

Julien Wintz's avatar
Julien Wintz committed
28
29
30
31
// ///////////////////////////////////////////////////////////////////

namespace dtkWidgetsMenuBarHelper {

32
void handle(const QList<QWidget *>& items, dtkWidgetsMenuBarContainer *c, dtkWidgetsMenuBar *mb = nullptr)
Julien Wintz's avatar
Julien Wintz committed
33
{
34
35
    auto setup = [=] (QWidget *facade, int i) {
        if (items.count() == 1 || (i > 1 && i < items.count() - 1 && dynamic_cast<dtkWidgetsMenuItemSpacerFacade *>(items.at(i - 1)) && dynamic_cast<dtkWidgetsMenuItemSpacerFacade *>(items.at(i + 1)))) {
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
36
            facade->setProperty("state", "alone");
37
38
39
        } else if (facade == items.last()) {
            facade->setProperty("state", "last");
            if(items.count() > 1 && dynamic_cast<dtkWidgetsMenuItemSpacerFacade *>(items.at(i - 1))) {
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
40
                facade->setProperty("state", "alone");
Julien Wintz's avatar
Julien Wintz committed
41
            }
42
43
44
45
46
        } else if (i < items.count() - 1 && dynamic_cast<dtkWidgetsMenuItemSpacerFacade *>(items.at(i + 1))) {
            facade->setProperty("state", "last");
        } else if (i == 0) {
            facade->setProperty("state", "first");
            if(items.count() > 1 && dynamic_cast<dtkWidgetsMenuItemSpacerFacade *>(items.at(i + 1))) {
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
47
                facade->setProperty("state", "alone");
48
49
50
51
52
            }
        } else if (i > 1 && dynamic_cast<dtkWidgetsMenuItemSpacerFacade *>(items.at(i - 1))) {
            facade->setProperty("state", "first");
        } else {
            facade->setProperty("state", "inner");
Julien Wintz's avatar
Julien Wintz committed
53
        }
54
    };
Julien Wintz's avatar
Julien Wintz committed
55

56
57
58
59
    int i = 0;
    for (QWidget *item : items) {
        if (!item)
            continue;
Julien Wintz's avatar
Julien Wintz committed
60

61
        if (dtkWidgetsMenuInnerFacade *facade = dynamic_cast<dtkWidgetsMenuInnerFacade *>(item)) {
Julien Wintz's avatar
Julien Wintz committed
62

63
            facade->parent_index = i;
Julien Wintz's avatar
Julien Wintz committed
64

65
66
67
            QObject::connect(facade, &dtkWidgetsMenuInnerFacade::clicked, [=](void) -> void
            {
                c->switchToNextSlide(facade->menu);
Julien Wintz's avatar
Julien Wintz committed
68

69
70
71
72
                if (mb && facade->parent_index >= 0) {
                    mb->setCurrentIndex(facade->parent_index);
                }
            });
Julien Wintz's avatar
Julien Wintz committed
73
74
        }

75
        setup(item, i++);
Julien Wintz's avatar
Julien Wintz committed
76
77
78
    }
}

79
} // namespace dtkWidgetsMenuBarHelper
Julien Wintz's avatar
Julien Wintz committed
80

81
// /////////////////////////////////////////////////////////////////////////////
82
//
83
84
// /////////////////////////////////////////////////////////////////////////////

Julien Wintz's avatar
Julien Wintz committed
85
86
87
88
89
class dtkWidgetsMenuBarButtonCollapse : public QLabel
{
    Q_OBJECT

public:
90
     dtkWidgetsMenuBarButtonCollapse(dtkWidgetsMenuBar *parent = nullptr);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
91
    ~dtkWidgetsMenuBarButtonCollapse(void);
Julien Wintz's avatar
Julien Wintz committed
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

signals:
    void clicked(void);

public:
    QSize sizeHint(void) const override;

protected:
    void mousePressEvent(QMouseEvent *) override;

public:
    void touch(void);

public:
    bool collapsed = true;
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
107
    QMetaObject::Connection m_connection;
108
109
110

public:
    dtkWidgetsMenuBar *q;
Julien Wintz's avatar
Julien Wintz committed
111
112
};

113
dtkWidgetsMenuBarButtonCollapse::dtkWidgetsMenuBarButtonCollapse(dtkWidgetsMenuBar *parent) : QLabel(parent)
Julien Wintz's avatar
Julien Wintz committed
114
{
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
115
    this->setAlignment(Qt::AlignCenter);
Julien Wintz's avatar
Julien Wintz committed
116
    this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
117
    this->setMouseTracking(true);
118
    this->q = parent;
Julien Wintz's avatar
Julien Wintz committed
119
    this->touch();
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
120
121
122
123
124
125
126
127
128
129

    m_connection = connect(dtkThemesEngine::instance(), &dtkThemesEngine::changed, [=]()
    {
        this->touch();
    });
}

dtkWidgetsMenuBarButtonCollapse::~dtkWidgetsMenuBarButtonCollapse(void)
{
    disconnect(m_connection);
Julien Wintz's avatar
Julien Wintz committed
130
131
132
133
}

QSize dtkWidgetsMenuBarButtonCollapse::sizeHint(void) const
{
134
    return QSize(q->d->size + 2 * q->d->margin, q->d->size + 2 * q->d->margin);
Julien Wintz's avatar
Julien Wintz committed
135
136
137
138
139
}

void dtkWidgetsMenuBarButtonCollapse::touch(void)
{
    dtkFontAwesome::instance()->initFontAwesome();
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
140
    dtkFontAwesome::instance()->setDefaultOption("color", dtkThemesEngine::instance()->color("@base7"));
Julien Wintz's avatar
Julien Wintz committed
141
142

    this->setToolTip(this->collapsed ? "Expand" : "Collapse");
143
    this->setPixmap(dtkFontAwesome::instance()->icon(this->collapsed ? fa::chevronright : fa::chevronleft).pixmap(QSize(q->d->size * 3 / 4, q->d->size * 3 / 4)));
Julien Wintz's avatar
Julien Wintz committed
144

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
145
    dtkThemesEngine::instance()->polish(this);
Julien Wintz's avatar
Julien Wintz committed
146
147
148
149
150
151
152
153
154
}

void dtkWidgetsMenuBarButtonCollapse::mousePressEvent(QMouseEvent *event)
{
    this->collapsed = !this->collapsed;

    this->emit clicked();

    this->touch();
Julien Wintz's avatar
Julien Wintz committed
155
156

    event->accept();
Julien Wintz's avatar
Julien Wintz committed
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// /////////////////////////////////////////////////////////////////////////////
// dtkWidgetsMenuBarButton
// /////////////////////////////////////////////////////////////////////////////

class dtkWidgetsMenuBarButton : public QLabel
{
    Q_OBJECT

public:
     dtkWidgetsMenuBarButton(int id, const QString &title, dtkWidgetsMenuBar *parent = nullptr);
    ~dtkWidgetsMenuBarButton(void);

signals:
    void clicked(void);

public slots:
    void touch(bool);

public:
    bool selected(void) const;

public:
    QSize sizeHint(void) const override;

protected:
    void mousePressEvent(QMouseEvent *) override;

    void enterEvent(QEvent *) override;
    void leaveEvent(QEvent *) override;

public:
    dtkWidgetsMenu *menu = nullptr;

private:
    bool m_selected = false;
    int icon_id = 0;
    QMetaObject::Connection m_connection;

private:
    dtkWidgetsMenuBar *q;
};

// /////////////////////////////////////////////////////////////////////////////
//
// /////////////////////////////////////////////////////////////////////////////

dtkWidgetsMenuBarButton::dtkWidgetsMenuBarButton(int id, const QString &title, dtkWidgetsMenuBar *parent) : QLabel(parent)
210
211
212
213
{
    this->icon_id = id;
    this->setAlignment(Qt::AlignCenter);
    this->setToolTip(title);
Julien Wintz's avatar
Julien Wintz committed
214
    this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
215
    this->setMouseTracking(true);
216

217
218
    this->q = parent;

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
219
220
    this->touch(false);

221
    m_connection = connect(dtkThemesEngine::instance(), &dtkThemesEngine::changed, [=]()
222
    {
223
        this->touch(this->m_selected);
224
    });
225
226
}

227
228
229
230
231
dtkWidgetsMenuBarButton::~dtkWidgetsMenuBarButton(void)
{
    disconnect(m_connection);
}

232
233
234
235
236
bool dtkWidgetsMenuBarButton::selected(void) const
{
    return this->m_selected;
}

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
237
void dtkWidgetsMenuBarButton::touch(bool selected)
238
{
239
    this->m_selected = selected;
240

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
241
242
243
    if (!selected) {
        dtkFontAwesome::instance()->setDefaultOption("color", dtkThemesEngine::instance()->color("@base7"));
        this->setProperty("state", "default");
244

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
245
246
247
248
    } else {
        dtkFontAwesome::instance()->setDefaultOption("color", dtkThemesEngine::instance()->color("@fg"));
        this->setProperty("state", "current");
    }
249

250
    this->setPixmap(dtkFontAwesome::instance()->icon(this->icon_id).pixmap(QSize(q->d->size * 3 / 4, q->d->size * 3 / 4)));
jwintz's avatar
jwintz committed
251

252
    dtkThemesEngine::instance()->polish(this);
253
254
255
256
}

QSize dtkWidgetsMenuBarButton::sizeHint(void) const
{
257
    return QSize(q->d->size, q->d->size);
258
259
}

Julien Wintz's avatar
Julien Wintz committed
260
void dtkWidgetsMenuBarButton::mousePressEvent(QMouseEvent *event)
261
262
{
    this->emit clicked();
Julien Wintz's avatar
Julien Wintz committed
263
264

    event->accept();
265
266
}

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
267
268
269
270
void dtkWidgetsMenuBarButton::enterEvent(QEvent *)
{
    dtkFontAwesome::instance()->setDefaultOption("color", dtkThemesEngine::instance()->color("@fg"));

271
    this->setPixmap(dtkFontAwesome::instance()->icon(this->icon_id).pixmap(QSize(q->d->size * 3 / 4, q->d->size * 3 / 4)));
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
272
273
274
275
}

void dtkWidgetsMenuBarButton::leaveEvent(QEvent *)
{
276
    if (!this->m_selected) {
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
277
        dtkFontAwesome::instance()->setDefaultOption("color", dtkThemesEngine::instance()->color("@base7"));
278
        this->setPixmap(dtkFontAwesome::instance()->icon(this->icon_id).pixmap(QSize(q->d->size * 3 / 4, q->d->size * 3 / 4)));
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
279
280
281
    }
}

282
// /////////////////////////////////////////////////////////////////////////////
283
//
284
// /////////////////////////////////////////////////////////////////////////////
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
285

286
dtkWidgetsMenuBarContainerSlide::dtkWidgetsMenuBarContainerSlide(dtkWidgetsMenuBar *q, dtkWidgetsMenuBarContainer *parent) : QFrame(parent)
Julien Wintz's avatar
Julien Wintz committed
287
{
288
289
    this->q = q;

Julien Wintz's avatar
Julien Wintz committed
290
291
292
293
294
295
296
297
298
299
300
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);
    layout->setAlignment(Qt::AlignTop);

    this->setAttribute(Qt::WA_NoSystemBackground);
    this->setAttribute(Qt::WA_TranslucentBackground);
}

301
dtkWidgetsMenuBarContainerSlide::dtkWidgetsMenuBarContainerSlide(dtkWidgetsMenuBar *q, dtkWidgetsMenu *m, dtkWidgetsMenuBarContainer *c) : QFrame(c), menu(m)
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
302
{
303
304
    this->q = q;

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
305
306
307
308
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    this->setFixedWidth(c->width());

    QVBoxLayout *layout = new QVBoxLayout(this);
Julien Wintz's avatar
Julien Wintz committed
309
    layout->setContentsMargins(0, 0, 0, 0);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
310
    layout->setSpacing(0);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
311
    layout->setAlignment(Qt::AlignTop);
312

313
    this->touch(m, c);
Julien Wintz's avatar
Julien Wintz committed
314
315
316

    this->setAttribute(Qt::WA_NoSystemBackground);
    this->setAttribute(Qt::WA_TranslucentBackground);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
317
318
}

319
dtkWidgetsMenuBarContainerSlide::dtkWidgetsMenuBarContainerSlide(dtkWidgetsMenuBar *q, dtkWidgetsMenuBar *mb, dtkWidgetsMenuBarContainer *c) : QFrame(c), menu_bar(mb)
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
320
{
321
322
    this->q = q;

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
323
324
325
326
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    this->setFixedWidth(c->width());

    QVBoxLayout *layout = new QVBoxLayout(this);
Julien Wintz's avatar
Julien Wintz committed
327
    layout->setContentsMargins(0, 0, 0, 0);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
328
    layout->setSpacing(0);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
329
    layout->setAlignment(Qt::AlignTop);
330

331
    this->touch(mb, c);
Julien Wintz's avatar
Julien Wintz committed
332
333
334

    this->setAttribute(Qt::WA_NoSystemBackground);
    this->setAttribute(Qt::WA_TranslucentBackground);
Julien Wintz's avatar
Julien Wintz committed
335
}
Julien Wintz's avatar
Julien Wintz committed
336

Julien Wintz's avatar
Julien Wintz committed
337
338
339
340
341
dtkWidgetsMenuBarContainerSlide::~dtkWidgetsMenuBarContainerSlide(void)
{
    menu = nullptr;
    menu_bar = nullptr;
}
Julien Wintz's avatar
Julien Wintz committed
342

343
void dtkWidgetsMenuBarContainerSlide::touch(dtkWidgetsMenu *m, dtkWidgetsMenuBarContainer *c)
344
345
{
    dtkWidgetsMenuFacade *facade = new dtkWidgetsMenuFacade(m);
Julien Wintz's avatar
Julien Wintz committed
346

347
    this->layout()->addWidget(new dtkWidgetsMenuItemSpacerFacade(q->d->margin/2, q->d->margin/2, this));
348
349
    this->layout()->addWidget(facade);

350
    ::dtkWidgetsMenuBarHelper::handle(facade->items(), c);
LE BRETON Come's avatar
LE BRETON Come committed
351
352

    static_cast<QBoxLayout *>(this->layout())->addStretch();
353
354
}

355
void dtkWidgetsMenuBarContainerSlide::touch(dtkWidgetsMenuBar *mb, dtkWidgetsMenuBarContainer *c)
Julien Wintz's avatar
Julien Wintz committed
356
{
357
    QLayoutItem *item = nullptr; while ((item = this->layout()->takeAt(0))) delete item->widget();
358

359
    for (dtkWidgetsMenu *m : mb->menus()) {
360

361
362
        dtkWidgetsMenuHeaderFacade *header = new dtkWidgetsMenuHeaderFacade(m);
        dtkWidgetsMenuFacade *widget = new dtkWidgetsMenuFacade(m);
LE BRETON Come's avatar
LE BRETON Come committed
363

364
365
        this->layout()->addWidget(header);
        this->layout()->addWidget(widget);
Julien Wintz's avatar
Julien Wintz committed
366

367
        ::dtkWidgetsMenuBarHelper::handle(widget->items(), c);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
368
    }
LE BRETON Come's avatar
LE BRETON Come committed
369

370
    this->layout()->addWidget(new dtkWidgetsMenuItemSpacerFacade(q->d->margin/2, q->d->margin/2, this));
Julien Wintz's avatar
Julien Wintz committed
371

LE BRETON Come's avatar
LE BRETON Come committed
372
    static_cast<QBoxLayout *>(this->layout())->addStretch();
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
373
}
374

Julien Wintz's avatar
Julien Wintz committed
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
void dtkWidgetsMenuBarContainerSlide::touch(const QVector<dtkWidgetsMenu *>& menus, dtkWidgetsMenuBarContainer *c)
{
    QLayoutItem *item = nullptr; while ((item = this->layout()->takeAt(0))) delete item->widget();

    for (dtkWidgetsMenu *m : menus) {

        dtkWidgetsMenuHeaderFacade *header = new dtkWidgetsMenuHeaderFacade(m);
        dtkWidgetsMenuFacade *widget = new dtkWidgetsMenuFacade(m);

        this->layout()->addWidget(header);
        this->layout()->addWidget(widget);

        ::dtkWidgetsMenuBarHelper::handle(widget->items(), c);
    }

390
391
392
    int margin; q ? margin = q->d->margin : margin = 12;

    this->layout()->addWidget(new dtkWidgetsMenuItemSpacerFacade(margin/2, margin/2, this));
Julien Wintz's avatar
Julien Wintz committed
393
394
395
396

    static_cast<QBoxLayout *>(this->layout())->addStretch();
}

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
397
398
399
400
// ///////////////////////////////////////////////////////////////////
// dtkWidgetsMenuBarContainer implementation
// ///////////////////////////////////////////////////////////////////

SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
401
402
dtkWidgetsMenuBarContainer::dtkWidgetsMenuBarContainer(QWidget *parent) : dtkWidgetsOverlayPane(parent)
{
Julien Wintz's avatar
Julien Wintz committed
403
    this->slider = new dtkWidgetsOverlayPaneSlider;
Julien Wintz's avatar
Julien Wintz committed
404
    this->slider->setBound(300);
SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
405
    this->slider->toggle();
406
    this->slider->enableSpying(true);
407

408
409
410
    this->navigator = new dtkWidgetsMenuNavigationFacade(this);

    this->addWidget(this->navigator);
411
    this->addWidget(this->slider);
412

Julien Wintz's avatar
Julien Wintz committed
413
414
    connect(navigator, &dtkWidgetsMenuNavigationFacade::clicked, [=] (void) -> void
    {
LE BRETON Come's avatar
LE BRETON Come committed
415
        if (this->slider->is_in_transition)
416
            return;
417
418
        dtkWidgetsMenu *menu = nullptr;

419
420
        if (this->stack.count())
            menu = this->stack.takeLast();
421
422
423

        this->switchToPrevSlide(menu);
    });
SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
424
425
}

426
dtkWidgetsMenuBarContainer::~dtkWidgetsMenuBarContainer(void)
SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
427
{
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
428

SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
429
430
}

431
432
433
434
435
int dtkWidgetsMenuBarContainer::stackCount(void) const
{
    return stack.count();
}

436
437
void dtkWidgetsMenuBarContainer::setCurrentIndex(int index, std::function<void ()>& callback)
{
438
    if (this->slider->is_in_transition)
439
440
        return;

441
442
443
    this->slider->enableSpying(false);
    this->slider->blockSignals(true);

Julien Wintz's avatar
Julien Wintz committed
444
445
    static std::function<void (void)> ca = [=] (void) -> void
    {
446
447
448
449
450
        this->slider->blockSignals(false);
        this->slider->enableSpying(true);
        callback();
    };

451
452
    std::function<void (void)> cb = [=] (void) -> void
    {
Julien Wintz's avatar
Julien Wintz committed
453
        this->slider->setCurrentIndex(index, ca);
454
455
    };

456
    if (this->stack.count())
457
458
459
460
461
462
        this->switchToRoot(cb);
    else
        cb();
}

void dtkWidgetsMenuBarContainer::switchToRoot(std::function<void(void)> &callback)
463
{
464
    if (this->slider->is_in_transition)
465
466
        return;

467
468
469
    this->navigator->setMenu(0);

    this->slider->enableSpying(false);
470
    this->slider->blockSignals(true);
471

472
    std::function<void(void)> cb = [=](void) -> void
Julien Wintz's avatar
Julien Wintz committed
473
    {
474
475
        while (!this->stack.isEmpty())
            this->slider->remSlide(this->slides[this->stack.takeLast()]);
476
477
478
479
480
481
482
483
484

        callback();

        this->slider->blockSignals(false);
        this->slider->enableSpying(false);
    };

    this->slider->slideTo(0, cb);
}
485

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
486
void dtkWidgetsMenuBarContainer::switchToPrevSlide(dtkWidgetsMenu *m)
Julien Wintz's avatar
Julien Wintz committed
487
{
488
    if (this->slider->is_in_transition)
489
490
        return;

491
492
    if (m)
        emit q->left(m);
Julien Wintz's avatar
Julien Wintz committed
493

494
495
    if (this->stack.count())
        this->navigator->setMenu(this->stack.last());
496
497
498
    else
        this->navigator->setMenu(0);

Julien Wintz's avatar
Julien Wintz committed
499
500
    std::function<void()> callback = [=] (void) -> void
    {
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
501
502
        this->slider->remSlide(this->slides[m]);
    };
Julien Wintz's avatar
Julien Wintz committed
503

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
504
    if (!m) {
Julien Wintz's avatar
Julien Wintz committed
505
506
        this->q->d->toggle->collapsed = !this->q->d->toggle->collapsed;
        this->q->d->toggle->touch();
Julien Wintz's avatar
Julien Wintz committed
507
        this->toggle();
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
508
    } else {
Julien Wintz's avatar
Julien Wintz committed
509
        this->slider->slideToPrevious(callback);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
510
    }
Julien Wintz's avatar
Julien Wintz committed
511

512
513
    if(this->stack.count())
        emit q->entered(this->stack.last());
Julien Wintz's avatar
Julien Wintz committed
514
515
}

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
516
void dtkWidgetsMenuBarContainer::switchToNextSlide(dtkWidgetsMenu *m)
Julien Wintz's avatar
Julien Wintz committed
517
{
518
    if (this->slider->is_in_transition)
519
520
        return;

521
522
    if(this->stack.count())
        emit q->left(this->stack.last());
Julien Wintz's avatar
Julien Wintz committed
523

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
524
525
    this->slider->addSlide(fa::cogs, this->slides[m]);
    this->slider->slideToNext();
526
527
528

    this->navigator->setMenu(m);

529
    this->stack << m;
Julien Wintz's avatar
Julien Wintz committed
530
531

    emit q->entered(m);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
532
}
Julien Wintz's avatar
Julien Wintz committed
533

534
535
void dtkWidgetsMenuBarContainer::touch(void)
{
536
    if (this->slider->is_in_transition)
537
538
        return;

539
    this->stack.clear();
540
    navigator->setMenu(0);
541
542
543
    this->master_slide->touch(this->master_menus, this);
}

544
void dtkWidgetsMenuBarContainer::touch(dtkWidgetsMenuBar *mb)
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
545
{
546
    if (this->slider->is_in_transition)
547
548
        return;

549
    this->stack.clear();
550
551
    navigator->setMenu(0);

Julien Wintz's avatar
Julien Wintz committed
552
    if(!this->master_slide) {
553
554

        this->master_slide = new dtkWidgetsMenuBarContainerSlide(this->q, mb, this);
Julien Wintz's avatar
Julien Wintz committed
555
        this->slider->addSlide(fa::cogs, this->master_slide);
Julien Wintz's avatar
Julien Wintz committed
556

557
    } else {
558

559
        qDeleteAll(this->slides);
560

561
        this->slides.clear();
562

563
        this->master_slide->touch(mb, this);
564
    }
565

566
567
568
569
    for (auto m : mb->menus()) {

        for (auto mm : m->menus()) {

570
            this->buildChildSlide(mm);
571
572
        }
    }
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
573
}
Julien Wintz's avatar
Julien Wintz committed
574

575
576
void dtkWidgetsMenuBarContainer::decr(void)
{
577
    if (this->slider->is_in_transition)
578
579
        return;

580
    this->slider->decr();
CABEL Tristan's avatar
CABEL Tristan committed
581

582
    this->stack.takeLast();
583
584
}

Julien Wintz's avatar
Julien Wintz committed
585
586
587
void dtkWidgetsMenuBarContainer::build(const QVector<dtkWidgetsMenu *>& menus)
{
    if(!this->master_slide) {
588
        this->master_slide = new dtkWidgetsMenuBarContainerSlide(q, this);
Julien Wintz's avatar
Julien Wintz committed
589
590
        this->slider->addSlide(fa::cogs, this->master_slide);
    }
CABEL Tristan's avatar
CABEL Tristan committed
591

Julien Wintz's avatar
Julien Wintz committed
592
    this->master_slide->touch(menus, this);
593
594

    this->master_menus = menus;
Julien Wintz's avatar
Julien Wintz committed
595
596
}

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
597
598
void dtkWidgetsMenuBarContainer::buildChildSlide(dtkWidgetsMenu *menu)
{
599
    dtkWidgetsMenuBarContainerSlide *slide = new dtkWidgetsMenuBarContainerSlide(q, menu, this);
600
    slide->setVisible(false);
601

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
602
603
    this->slides.insert(menu, slide);

604
    for (auto m : menu->menus())
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
605
        this->buildChildSlide(m);
SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
606
607
}

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
608
// ///////////////////////////////////////////////////////////////////
609
// dtkWidgetsMenuBarPrivate
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
610
// ///////////////////////////////////////////////////////////////////
611

612
void dtkWidgetsMenuBarPrivate::touch(void)
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
613
{
614
    QLayoutItem *child; while ((child = this->layout->takeAt(0)) != 0) delete child->widget();
615

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
616
    for (dtkWidgetsMenu *m : menu_list) {
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
617

Julien Wintz's avatar
Julien Wintz committed
618
        dtkWidgetsMenuBarButton *b = new dtkWidgetsMenuBarButton(m->icon(), m->title(), q);
SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
619
        b->menu = m;
620

Julien Wintz's avatar
Julien Wintz committed
621
        QObject::connect(b, &dtkWidgetsMenuBarButton::clicked, [=] (void) -> void {
622

Julien Wintz's avatar
Julien Wintz committed
623
            int index = 0;
624
            int target = 0;
625
            bool selected = b->selected();
626

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
627
            for (int i = 0; i < this->layout->count(); ++i) {
628

Julien Wintz's avatar
Julien Wintz committed
629
                if (dtkWidgetsMenuBarButton *button = dynamic_cast<dtkWidgetsMenuBarButton *>(this->layout->itemAt(i)->widget())) {
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
630
                    if (button == b) {
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
631
                        button->touch(true);
632
                        target = index;
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
633
634
                    } else {
                        button->touch(false);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
635
                    }
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
636
                    ++index;
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
637
                }
638
            }
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
639

640
641
642
643
644
            std::function<void(void)> callback = [=](void) -> void {
                this->c->blockSignals(false);
                this->c->slider->blockSignals(false);
                q->emit clicked(target);
            };
645

646
            if(!this->c->width() || selected) {
Julien Wintz's avatar
Julien Wintz committed
647
648
                this->toggle->collapsed = !this->toggle->collapsed;
                this->toggle->touch();
Julien Wintz's avatar
Julien Wintz committed
649
                this->c->slider->blockSignals(true);
Julien Wintz's avatar
Julien Wintz committed
650
                this->c->blockSignals(true);
651
                this->c->toggle(callback);
652
            } else {
653
                callback();
654
            }
655
        });
656

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
657
658
        this->layout->addWidget(b);
    }
659
660

    this->toggle->touch();
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
661
662
}

663
// ///////////////////////////////////////////////////////////////////
Julien Wintz's avatar
Julien Wintz committed
664
// dtkWidgetsMenuBar
665
666
// ///////////////////////////////////////////////////////////////////

667
dtkWidgetsMenuBar::dtkWidgetsMenuBar(QWidget *parent) : QFrame(parent), d(new dtkWidgetsMenuBarPrivate)
668
{
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
669
670
    d->q = this;

671
672
    // QGraphicsBlurEffect *effect = new QGraphicsBlurEffect(this);
    // effect->setBlurRadius(20);
673

674
    // this->setGraphicsEffect(effect);
675

676
    d->c = new dtkWidgetsMenuBarContainer(parent);
Julien Wintz's avatar
Julien Wintz committed
677
    d->c->q = this;
SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
678
679
    d->c->toggle();
    d->c->toggle();
Julien Wintz's avatar
Julien Wintz committed
680
681

    connect(d->c->slider, SIGNAL(indexVisible(int)), d->c, SIGNAL(indexVisible(int)));
SZPYRKA Jean-Luc's avatar
PoC PoC    
SZPYRKA Jean-Luc committed
682

Julien Wintz's avatar
Julien Wintz committed
683
    d->s = new dtkWidgetsMenuSpy;
Julien Wintz's avatar
Julien Wintz committed
684
685
686
    d->s->setMenuBar(this);
    d->s->setMenuBarContainer(d->c);

687
    d->layout = new QVBoxLayout;
688
689
    d->layout->setContentsMargins(d->margin, d->margin, d->margin, d->margin);
    d->layout->setSpacing(d->margin);
690
691
    d->layout->setAlignment(Qt::AlignTop);

Julien Wintz's avatar
Julien Wintz committed
692
693
    QFrame *viewport = new QFrame(this);
    viewport->setLayout(d->layout);
694
    viewport->setFixedWidth(d->size + 2 * d->margin);
695

Julien Wintz's avatar
Julien Wintz committed
696
697
698
699
700
701
    d->scroll = new QScrollArea(this);
    d->scroll->setFrameShape(QFrame::NoFrame);
    d->scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    d->scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    d->scroll->setWidgetResizable(true);
    d->scroll->setWidget(viewport);
702

Julien Wintz's avatar
Julien Wintz committed
703
704
705
706
707
708
709
710
711
712
713
714
715
    d->toggle = new dtkWidgetsMenuBarButtonCollapse(this);

    static std::function<void(void)> callback = [=] (void) -> void {

        d->c->blockSignals(false);
        d->c->slider->blockSignals(false);
    };

    connect(d->toggle, &dtkWidgetsMenuBarButtonCollapse::clicked, [=] (void) -> void {
        d->c->slider->blockSignals(true);
        d->c->blockSignals(true);
        d->c->toggle(callback);
    });
716

717
    this->setFixedWidth(d->size + 2 * d->margin);
718
719
}

720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
void dtkWidgetsMenuBar::toggle(void)
{
    d->toggle->collapsed = !d->toggle->collapsed;
    emit d->toggle->clicked();
    d->toggle->touch();
}

void dtkWidgetsMenuBar::collapse(void)
{
    if (d->toggle->collapsed == false) {
        this->toggle();
    }
}

void dtkWidgetsMenuBar::expand(void)
{
    if (d->toggle->collapsed) {
        this->toggle();
    }
}

741
742
743
744
745
dtkWidgetsMenuBar::~dtkWidgetsMenuBar(void)
{
    delete d;
}

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
746
dtkWidgetsMenu *dtkWidgetsMenuBar::addMenu(dtkWidgetsMenu *menu)
747
{
748
    if (menu && !d->menu_hash.contains(menu->title())) {
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
749
        menu->setParent(this);
750

751
        d->menu_hash.insert(menu->title(), menu);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
752
        d->menu_list << menu;
753

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
754
755
        return menu;
    }
756

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
757
    return nullptr;
758
759
}

760
dtkWidgetsMenu *dtkWidgetsMenuBar::addMenu(int icon_id, const QString &title)
761
{
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
762
    dtkWidgetsMenu *menu = new dtkWidgetsMenu(icon_id, title);
Julien Wintz's avatar
Julien Wintz committed
763

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
764
    auto m = this->addMenu(menu);
Julien Wintz's avatar
Julien Wintz committed
765

766
    if (m != menu)
767
      delete menu;
Julien Wintz's avatar
Julien Wintz committed
768

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
769
770
771
772
773
    return m;
}

dtkWidgetsMenu *dtkWidgetsMenuBar::insertMenu(int pos, dtkWidgetsMenu *menu)
{
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
774
    if (pos < 0 || pos > d->menu_list.size() || !menu || d->menu_hash.contains(menu->title())) {
775
      return nullptr;
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
776
    }
Julien Wintz's avatar
Julien Wintz committed
777

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
778
    menu->setParent(this);
Julien Wintz's avatar
Julien Wintz committed
779

780
    d->menu_hash.insert(menu->title(), menu);
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
781
    d->menu_list.insert(pos, menu);
Julien Wintz's avatar
Julien Wintz committed
782

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
783
784
785
    return menu;
}

786
dtkWidgetsMenu *dtkWidgetsMenuBar::insertMenu(int pos, int icon_id, const QString &title)
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
787
{
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
788
    dtkWidgetsMenu *menu = new dtkWidgetsMenu(icon_id, title);
789

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
790
    auto m = this->insertMenu(pos, menu);
791
792

    if (m != menu)
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
793
        delete menu;
794

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
795
796
797
798
799
    return m;
}

void dtkWidgetsMenuBar::removeMenu(dtkWidgetsMenu *menu)
{
800
801
    if (!menu)
        return;
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
802

803
    this->removeMenu(menu->title());
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
804
}
805

806
void dtkWidgetsMenuBar::removeMenu(const QString &title)
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
807
{
808
809
    auto m = d->menu_hash.take(title);

KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
810
811
    if (m) {
        d->menu_list.removeOne(m);
812
        d->touch();
KLOCZKO Thibaud's avatar
KLOCZKO Thibaud committed
813
814
815
    }
}

816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
// /////////////////////////////////////////////////////////////////////////////
//
// /////////////////////////////////////////////////////////////////////////////

void build(QMenu *menu, dtkWidgetsMenu *w_menu)
{
    foreach(QAction *action, menu->actions()) {

        dtkWidgetsMenu *w_s_menu = 0;

        if(QMenu *s_menu = action->menu()) {

            w_s_menu = w_menu->addMenu(fa::circle, action->text());

            build(s_menu, w_s_menu);
        } else {

            if(action->isSeparator()) {
                w_menu->addSeparator();
            } else {

                dtkWidgetsMenuItem *item = w_menu->addItem(fa::dashcube, action->text());

                QObject::connect(item, SIGNAL(clicked()), action, SLOT(trigger()));
            }
        }
    }
}

// /////////////////////////////////////////////////////////////////////////////

QList<dtkWidgetsMenu *> dtkWidgetsMenuBar::build(const QString& prefix, QMenuBar *bar)
{
    QList<dtkWidgetsMenu *> menus;

    foreach(QAction *action, bar->actions()) {

        if(action->text().isEmpty())
            continue;

        dtkWidgetsMenu *w_menu = new dtkWidgetsMenu(fa::circle, QString(prefix + "::" + action->text()));

        ::build(action->menu(), w_menu);

        menus << w_menu;
    }
862

863
864
865
    return menus;
}

866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
dtkWidgetsMenu *dtkWidgetsMenuBar::build(QMenu *menu)
{
    dtkWidgetsMenu *w_menu = new dtkWidgetsMenu(fa::circle, menu->title());

    foreach(QAction *action, menu->actions()) {

        if(action->text().isEmpty())
            continue;

        // ::build(action, w_menu);

        dtkWidgetsMenu *w_s_menu = 0;

        if(QMenu *s_menu = action->menu()) {

            w_s_menu = w_menu->addMenu(fa::circle, action->text());

            ::build(s_menu, w_s_menu);
        } else {

            if(action->isSeparator()) {
                w_menu->addSeparator();
            } else {

                dtkWidgetsMenuItem *item = w_menu->addItem(fa::dashcube, action->text());

                QObject::connect(item, SIGNAL(clicked()), action, SLOT(trigger()));
            }
        }
    }

    return w_menu;
}

Julien Wintz's avatar
Julien Wintz committed
900
901
902
903
dtkWidgetsMenu *dtkWidgetsMenuBar::menu(const QString& id)
{
    QStringList path = id.split(":", QString::SkipEmptyParts);

Julien Wintz's avatar
Julien Wintz committed
904
905
906
    if(path.isEmpty())
        return nullptr;

907
908
909
    if(!d->menu_hash.contains(path.first()))
        return nullptr;

Julien Wintz's avatar
Julien Wintz committed
910
    dtkWidgetsMenu *root = d->menu_hash[path.takeFirst()];
911
    dtkWidgetsMenu *meny = root;
Julien Wintz's avatar
Julien Wintz committed
912
913
914
915
916
917
918
919
920
921
922
923
924
925

    std::function<void (dtkWidgetsMenu *)> sniff = [&] (dtkWidgetsMenu *menu) -> void {

        if(path.isEmpty())
            return;

        QObject *object = menu->object(path.takeFirst());

        if (dtkWidgetsMenu *m = qobject_cast<dtkWidgetsMenu *>(object)) {
            meny = m;
            sniff(m);
        }
    };

LE BRETON Come's avatar
LE BRETON Come committed
926
927
    if(root)
        sniff(root);