├── designer_plugin
├── icon.png
├── resource.qrc
├── designerplugin.pro
├── burgermenuplugin.h
└── burgermenuplugin.cpp
├── example
├── images
│ ├── albums.png
│ ├── burger.png
│ ├── folders.png
│ ├── preview.jpg
│ └── collections.png
├── resource.qrc
├── example.pro
└── main.cpp
├── .gitignore
├── README.md
├── LICENSE
└── src
├── burgermenu.h
└── burgermenu.cpp
/designer_plugin/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisaverage/burger-menu/HEAD/designer_plugin/icon.png
--------------------------------------------------------------------------------
/example/images/albums.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisaverage/burger-menu/HEAD/example/images/albums.png
--------------------------------------------------------------------------------
/example/images/burger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisaverage/burger-menu/HEAD/example/images/burger.png
--------------------------------------------------------------------------------
/example/images/folders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisaverage/burger-menu/HEAD/example/images/folders.png
--------------------------------------------------------------------------------
/example/images/preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisaverage/burger-menu/HEAD/example/images/preview.jpg
--------------------------------------------------------------------------------
/designer_plugin/resource.qrc:
--------------------------------------------------------------------------------
1 |
icon.png
2 |
--------------------------------------------------------------------------------
/example/images/collections.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisaverage/burger-menu/HEAD/example/images/collections.png
--------------------------------------------------------------------------------
/example/resource.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | images/burger.png
4 | images/collections.png
5 | images/folders.png
6 | images/albums.png
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/example.pro:
--------------------------------------------------------------------------------
1 | QT += core gui widgets
2 |
3 | TARGET = example
4 | TEMPLATE = app
5 |
6 | CONFIG += c++11
7 |
8 | RESOURCES += resource.qrc
9 |
10 | HEADERS += ../src/burgermenu.h
11 |
12 | SOURCES += main.cpp\
13 | ../src/burgermenu.cpp
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # C++ objects and libs
2 |
3 | *.slo
4 | *.lo
5 | *.o
6 | *.a
7 | *.la
8 | *.lai
9 | *.so
10 | *.dll
11 | *.dylib
12 |
13 | # Qt-es
14 |
15 | /.qmake.cache
16 | /.qmake.stash
17 | *.pro.user
18 | *.pro.user.*
19 | *.qbs.user
20 | *.qbs.user.*
21 | *.moc
22 | moc_*.cpp
23 | qrc_*.cpp
24 | ui_*.h
25 | Makefile*
26 | */build/*
27 |
28 | # QtCreator
29 |
30 | *.autosave
31 |
32 | #QtCtreator Qml
33 | *.qmlproject.user
34 | *.qmlproject.user.*
35 |
--------------------------------------------------------------------------------
/designer_plugin/designerplugin.pro:
--------------------------------------------------------------------------------
1 | CONFIG += plugin debug_and_release
2 |
3 | QT += designer
4 |
5 | TEMPLATE = lib
6 |
7 | TARGET = burgermenu
8 |
9 | HEADERS = burgermenuplugin.h \
10 | ../src/burgermenu.h
11 |
12 | SOURCES = burgermenuplugin.cpp \
13 | ../src/burgermenu.cpp
14 |
15 | INCLUDEPATH += ../src/
16 |
17 | RESOURCES = resource.qrc
18 |
19 | target.path = $$[QT_INSTALL_PLUGINS]/designer
20 |
21 | INSTALLS += target
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # burger-menu
2 | A basic burger menu widget implementation for Qt.
3 |
4 | Menu entries are added as QActions with support for text and icons, like in regular QMenu.
5 | Burget menu icon is user configurable.
6 | Menu expansion is optionally animated.
7 | Signals are provided for all state changes and triggering of the actions.
8 | Theme is configurable via standard stylesheet box model referring to object names:
9 | - *#BurgerMenu* - the entire menu widget
10 | - *#BurgerButton* - a single entry on the list
11 | - *#MainBurgerButton* - the burger menu button
12 |
13 | An optional Qt Designer plugin is provided to ease integrating this widget with .ui classes, but due to restrictions of designer API actions need to be added from code.
14 |
15 | Example look:
16 |
17 | 
18 |
--------------------------------------------------------------------------------
/designer_plugin/burgermenuplugin.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class BurgerMenuPlugin : public QObject, public QDesignerCustomWidgetInterface
6 | {
7 | Q_OBJECT
8 | Q_INTERFACES(QDesignerCustomWidgetInterface)
9 | #if QT_VERSION >= 0x050000
10 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")
11 | #endif // QT_VERSION >= 0x050000
12 |
13 | public:
14 | BurgerMenuPlugin(QObject *parent = 0);
15 |
16 | bool isContainer() const;
17 | bool isInitialized() const;
18 | QIcon icon() const;
19 | QString domXml() const;
20 | QString group() const;
21 | QString includeFile() const;
22 | QString name() const;
23 | QString toolTip() const;
24 | QString whatsThis() const;
25 | QWidget *createWidget(QWidget *parent);
26 | void initialize(QDesignerFormEditorInterface *core);
27 |
28 | private:
29 | bool m_initialized;
30 | };
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Krzysztof Kawa
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/designer_plugin/burgermenuplugin.cpp:
--------------------------------------------------------------------------------
1 | #include "burgermenu.h"
2 | #include "burgermenuplugin.h"
3 | #include
4 |
5 | BurgerMenuPlugin::BurgerMenuPlugin(QObject *parent)
6 | : QObject(parent)
7 | {
8 | m_initialized = false;
9 | }
10 |
11 | void BurgerMenuPlugin::initialize(QDesignerFormEditorInterface * /* core */)
12 | {
13 | if (m_initialized)
14 | return;
15 |
16 | // Add extension registrations, etc. here
17 |
18 | m_initialized = true;
19 | }
20 |
21 | bool BurgerMenuPlugin::isInitialized() const
22 | {
23 | return m_initialized;
24 | }
25 |
26 | QWidget *BurgerMenuPlugin::createWidget(QWidget *parent)
27 | {
28 | return new BurgerMenu(parent);
29 | }
30 |
31 | QString BurgerMenuPlugin::name() const
32 | {
33 | return QLatin1String("BurgerMenu");
34 | }
35 |
36 | QString BurgerMenuPlugin::group() const
37 | {
38 | return QLatin1String("Menus");
39 | }
40 |
41 | QIcon BurgerMenuPlugin::icon() const
42 | {
43 | return QIcon(QLatin1String(":/icon.png"));
44 | }
45 |
46 | QString BurgerMenuPlugin::toolTip() const
47 | {
48 | return QLatin1String("Burger Menu");
49 | }
50 |
51 | QString BurgerMenuPlugin::whatsThis() const
52 | {
53 | return QLatin1String("A widget implementing burger menu.");
54 | }
55 |
56 | bool BurgerMenuPlugin::isContainer() const
57 | {
58 | return false;
59 | }
60 |
61 | QString BurgerMenuPlugin::domXml() const
62 | {
63 | return QLatin1String("\n");
64 | }
65 |
66 | QString BurgerMenuPlugin::includeFile() const
67 | {
68 | return QLatin1String("burgermenu.h");
69 | }
70 | #if QT_VERSION < 0x050000
71 | Q_EXPORT_PLUGIN2(burgermenuplugin, BurgerMenuPlugin)
72 | #endif // QT_VERSION < 0x050000
73 |
--------------------------------------------------------------------------------
/src/burgermenu.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | class QPushButton;
8 | class QActionGroup;
9 | class QAction;
10 | class QString;
11 | class BurgerButton;
12 |
13 | class BurgerMenu : public QWidget
14 | {
15 | Q_OBJECT
16 | Q_PROPERTY(QIcon icon READ burgerIcon WRITE setBurgerIcon NOTIFY iconChanged)
17 | Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged)
18 | Q_PROPERTY(int menuWidth READ menuWidth WRITE setMenuWidth NOTIFY menuWidthChanged)
19 | Q_PROPERTY(bool animated READ animated WRITE setAnimated NOTIFY animatedChanged)
20 | Q_PROPERTY(bool expanded READ expanded WRITE setExpanded NOTIFY expandedChanged)
21 |
22 | public:
23 | BurgerMenu(QWidget* parent = nullptr);
24 |
25 | QIcon burgerIcon() const;
26 | QSize iconSize() const;
27 | int menuWidth() const;
28 | QList actions() const;
29 | bool animated() const;
30 | bool expanded() const;
31 |
32 | signals:
33 | void iconChanged();
34 | void iconSizeChanged(const QSize& size);
35 | void menuWidthChanged(int width);
36 | void animatedChanged(bool animated);
37 | void expandedChanged(bool expanded);
38 | void triggered(QAction* action);
39 |
40 | public slots:
41 | QAction* addMenuAction(QAction* action);
42 | QAction* addMenuAction(const QString& label);
43 | QAction* addMenuAction(const QIcon& icon, const QString& label);
44 | void removeMenuAction(QAction* action);
45 |
46 | void setBurgerIcon(const QIcon& icon);
47 | void setIconSize(const QSize& size);
48 | void setMenuWidth(int width);
49 | void setAnimated(bool animated);
50 | void setExpanded(bool expanded);
51 |
52 | protected:
53 | void paintEvent(QPaintEvent*) override;
54 |
55 | private:
56 | void registerAction(QAction* action);
57 | void unRegisterAction(QAction* action);
58 | void setExpansionState(bool expanded);
59 |
60 | QActionGroup* mActions;
61 | QPushButton* mBurgerButton;
62 | QList mActionButtons;
63 | int mMenuWidth;
64 | bool mAnimated;
65 | };
66 |
--------------------------------------------------------------------------------
/example/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "../src/burgermenu.h"
7 |
8 |
9 | int main(int argc, char *argv[])
10 | {
11 | QApplication a(argc, argv);
12 |
13 | QWidget window;
14 | window.setMinimumSize(500, 400);
15 |
16 | BurgerMenu* menu = new BurgerMenu();
17 | QTextEdit* textEdit = new QTextEdit();
18 |
19 | window.setLayout(new QHBoxLayout());
20 | window.layout()->setContentsMargins(0,0,0,0);
21 | window.layout()->setSpacing(0);
22 | window.layout()->addWidget(menu);
23 | window.layout()->addWidget(textEdit);
24 |
25 | menu->setMenuWidth(100);
26 | menu->setBurgerIcon(QIcon(":/images/burger.png"));
27 | menu->addMenuAction(QIcon(":/images/collections.png"), "Collection");
28 | menu->addMenuAction(QIcon(":/images/folders.png"), "Folders");
29 | menu->addMenuAction(QIcon(":/images/albums.png"), "Albums");
30 |
31 | window.setStyleSheet("BurgerMenu { background-color: black; }"
32 | "#BurgerMenu { background-color: black; }"
33 | "#BurgerButton { background-color: black; color: white; font-size: 18px; }"
34 | "#BurgerButton:hover { background-color: #3480D2; }"
35 | "#BurgerButton:checked { background-color: #106EBE; }"
36 | "#BurgerButton:checked:hover { background-color: #3480D2; }"
37 | "#MainBurgerButton { background-color: black; border: none; } "
38 | "#MainBurgerButton:hover { background-color: #333; } "
39 | );
40 |
41 | QObject::connect(menu, &BurgerMenu::triggered, textEdit, [&](QAction* action)
42 | {
43 | textEdit->setText(QString("Action \"%1\" clicked.").arg(action->iconText()));
44 | });
45 |
46 | QObject::connect(menu, &BurgerMenu::expandedChanged, textEdit, [&](bool expanded)
47 | {
48 | textEdit->setText(QString("Expanded changed: %1").arg(expanded ? "expanded" : "collapsed"));
49 | });
50 |
51 | window.show();
52 | return a.exec();
53 | }
54 |
--------------------------------------------------------------------------------
/src/burgermenu.cpp:
--------------------------------------------------------------------------------
1 | #include "burgermenu.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | namespace ObjectNames
11 | {
12 | static const QLatin1String BurgerButton ("BurgerButton");
13 | static const QLatin1String BurgerMenu ("BurgerMenu");
14 | static const QLatin1String MainBurgerButton ("MainBurgerButton");
15 | }
16 |
17 | class BurgerButton : public QPushButton
18 | {
19 | public:
20 | BurgerButton(QAction* action, QWidget* parent)
21 | : QPushButton(parent)
22 | , mIconSize(QSize(64,64))
23 | , mAction(action)
24 | {
25 | connect(action, &QAction::destroyed, this, &BurgerButton::deleteLater);
26 | setCursor(Qt::PointingHandCursor);
27 |
28 | connect(mAction, &QAction::changed, this, static_cast(&BurgerButton::update));
29 | connect(this, &BurgerButton::clicked, mAction, [&]
30 | {
31 | if(mAction->isCheckable() && !mAction->isChecked())
32 | mAction->toggle();
33 |
34 | mAction->trigger();
35 | });
36 | }
37 |
38 | void paintEvent(QPaintEvent*) override
39 | {
40 | QPainter painter(this);
41 | QStyleOptionButton opt;
42 | opt.initFrom(this);
43 | opt.state |= (mAction->isChecked() ? QStyle::State_On : QStyle::State_Off);
44 |
45 | style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
46 | const QRect contentsRect = style()->subElementRect(QStyle::SE_PushButtonContents, &opt, this);
47 | if(!mAction->icon().isNull())
48 | {
49 | QIcon::Mode mode = ((opt.state & QStyle::State_MouseOver) == 0) ? QIcon::Normal : QIcon::Active;
50 | if(!isEnabled())
51 | mode = QIcon::Disabled;
52 | QIcon::State state = mAction->isChecked() ? QIcon::On : QIcon::Off;
53 | painter.drawPixmap(QRect(contentsRect.topLeft(), mIconSize), mAction->icon().pixmap(mIconSize, mode, state));
54 | }
55 |
56 | opt.rect = contentsRect.adjusted(mIconSize.width()+1, 0, 0, 0);
57 | opt.text = fontMetrics().elidedText(mAction->iconText(), Qt::ElideRight, opt.rect.width(), Qt::TextShowMnemonic);
58 | style()->drawControl(QStyle::CE_CheckBoxLabel, &opt, &painter, this);
59 | }
60 |
61 | void setIconSize(const QSize& size)
62 | {
63 | mIconSize = size;
64 | setFixedHeight(mIconSize.height());
65 | update();
66 | }
67 |
68 | QAction* action() const
69 | {
70 | return mAction;
71 | }
72 |
73 | private:
74 | QSize mIconSize;
75 | QAction* mAction;
76 | };
77 |
78 | BurgerMenu::BurgerMenu(QWidget* parent)
79 | : QWidget(parent)
80 | , mActions(new QActionGroup(this))
81 | , mBurgerButton(new QPushButton(this))
82 | , mMenuWidth(200)
83 | , mAnimated(true)
84 | {
85 | setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
86 | mBurgerButton->setObjectName(ObjectNames::MainBurgerButton);
87 | mBurgerButton->setFlat(true);
88 | mBurgerButton->setIconSize(QSize(48,48));
89 | mBurgerButton->setFixedSize(48,48);
90 | mBurgerButton->setCheckable(true);
91 | mBurgerButton->setCursor(Qt::PointingHandCursor);
92 | mActions->setExclusive(true);
93 |
94 | auto burgerWidget = new QWidget(this);
95 | burgerWidget->setObjectName(ObjectNames::BurgerMenu);
96 | auto burgerLay = new QHBoxLayout();
97 | burgerLay->setContentsMargins(0, 0, 0, 0);
98 | burgerLay->setSpacing(0);
99 | burgerLay->addWidget(mBurgerButton);
100 | burgerLay->addWidget(burgerWidget);
101 |
102 | auto lay = new QVBoxLayout();
103 | setLayout(lay);
104 | lay->setContentsMargins(0,0,0,0);
105 | lay->setSpacing(0);
106 |
107 | lay->addLayout(burgerLay);
108 | lay->addStretch();
109 | setFixedWidth(48);
110 |
111 | connect(mBurgerButton, &QPushButton::toggled, this, &BurgerMenu::setExpansionState);
112 | connect(mBurgerButton, &QPushButton::toggled, this, &BurgerMenu::expandedChanged);
113 | connect(mActions, &QActionGroup::triggered, this, &BurgerMenu::triggered);
114 | }
115 |
116 | QIcon BurgerMenu::burgerIcon() const
117 | {
118 | return mBurgerButton->icon();
119 | }
120 |
121 | QSize BurgerMenu::iconSize() const
122 | {
123 | return mBurgerButton->iconSize();
124 | }
125 |
126 | int BurgerMenu::menuWidth() const
127 | {
128 | return mMenuWidth;
129 | }
130 |
131 | QList BurgerMenu::actions() const
132 | {
133 | return mActions->actions();
134 | }
135 |
136 | QAction* BurgerMenu::addMenuAction(QAction* action)
137 | {
138 | mActions->addAction(action);
139 | registerAction(action);
140 | return action;
141 | }
142 |
143 | QAction*BurgerMenu::addMenuAction(const QString& label)
144 | {
145 | auto action = mActions->addAction(label);
146 | action->setCheckable(true);
147 | registerAction(action);
148 | return action;
149 | }
150 |
151 | QAction*BurgerMenu::addMenuAction(const QIcon& icon, const QString& label)
152 | {
153 | auto action = mActions->addAction(icon, label);
154 | action->setCheckable(true);
155 | registerAction(action);
156 | return action;
157 | }
158 |
159 | void BurgerMenu::removeMenuAction(QAction* action)
160 | {
161 | mActions->removeAction(action);
162 | unRegisterAction(action);
163 | }
164 |
165 | void BurgerMenu::setBurgerIcon(const QIcon& icon)
166 | {
167 | mBurgerButton->setIcon(icon);
168 | emit iconChanged();
169 | }
170 |
171 | void BurgerMenu::setIconSize(const QSize& size)
172 | {
173 | if(size == mBurgerButton->iconSize())
174 | return;
175 |
176 | mBurgerButton->setIconSize(size);
177 | mBurgerButton->setFixedSize(size);
178 | for(auto btn : std::as_const(mActionButtons))
179 | btn->setIconSize(size);
180 |
181 | if(mBurgerButton->isChecked())
182 | setFixedWidth(mBurgerButton->width() + mMenuWidth);
183 | else
184 | setFixedWidth(mBurgerButton->width());
185 |
186 | emit iconSizeChanged(size);
187 | }
188 |
189 | void BurgerMenu::setMenuWidth(int width)
190 | {
191 | if(width == mMenuWidth)
192 | return;
193 |
194 | mMenuWidth = width;
195 |
196 | if(mBurgerButton->isChecked())
197 | setFixedWidth(mBurgerButton->width() + mMenuWidth);
198 | else
199 | setFixedWidth(mBurgerButton->width());
200 |
201 | emit menuWidthChanged(mMenuWidth);
202 | }
203 |
204 | void BurgerMenu::setExpansionState(bool expanded)
205 | {
206 | if(mAnimated)
207 | {
208 | auto anim = new QPropertyAnimation(this, "minimumWidth", this);
209 | anim->setDuration(250);
210 | anim->setStartValue(mBurgerButton->width());
211 | anim->setEndValue(mBurgerButton->width() + mMenuWidth);
212 | anim->setDirection(expanded ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
213 | anim->setEasingCurve(expanded ? QEasingCurve::OutCubic : QEasingCurve::InCubic);
214 | anim->start(QAbstractAnimation::DeleteWhenStopped);
215 | }
216 | else
217 | {
218 | if(expanded)
219 | setFixedWidth(mBurgerButton->width() + mMenuWidth);
220 | else
221 | setFixedWidth(mBurgerButton->width());
222 | }
223 | }
224 |
225 | void BurgerMenu::registerAction(QAction* action)
226 | {
227 | auto button = new BurgerButton(action, this);
228 | button->setObjectName(ObjectNames::BurgerButton);
229 | button->setIconSize(mBurgerButton->iconSize());
230 | auto lay = static_cast(layout());
231 | lay->insertWidget(lay->count() - 1, button);
232 | mActionButtons << button;
233 | }
234 |
235 | void BurgerMenu::unRegisterAction(QAction* action)
236 | {
237 | auto btn = std::find_if(mActionButtons.begin(), mActionButtons.end(), [&](BurgerButton* btn){ return btn->action() == action; });
238 | if(btn != mActionButtons.end())
239 | {
240 | delete *btn;
241 | mActionButtons.erase(btn);
242 | }
243 | }
244 |
245 | bool BurgerMenu::animated() const
246 | {
247 | return mAnimated;
248 | }
249 |
250 | bool BurgerMenu::expanded() const
251 | {
252 | return mBurgerButton->isChecked();
253 | }
254 |
255 | void BurgerMenu::setAnimated(bool animated)
256 | {
257 | if(mAnimated == animated)
258 | return;
259 |
260 | mAnimated = animated;
261 | emit animatedChanged(mAnimated);
262 | }
263 |
264 | void BurgerMenu::setExpanded(bool expanded)
265 | {
266 | mBurgerButton->setChecked(expanded);
267 | }
268 |
269 | void BurgerMenu::paintEvent(QPaintEvent*)
270 | {
271 | QPainter painter(this);
272 | QStyleOption opt;
273 | opt.initFrom(this);
274 | style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
275 | }
276 |
--------------------------------------------------------------------------------