Krita Source Code Documentation
Loading...
Searching...
No Matches
KoToolBox.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005-2009 Thomas Zander <zander@kde.org>
3 * SPDX-FileCopyrightText: 2009 Peter Simonsson <peter.simonsson@gmail.com>
4 * SPDX-FileCopyrightText: 2010 Cyrille Berger <cberger@cberger.net>
5 * SPDX-FileCopyrightText: 2022 Alvin Wong <alvin@alvinhc.com>
6 *
7 * SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9
10#include "KoToolBox_p.h"
11#include "KoToolBoxLayout_p.h"
12#include "KoToolBoxButton_p.h"
13#include "kis_assert.h"
14
15#include <QButtonGroup>
16#include <QToolButton>
17#include <QStyleOption>
18#include <QActionGroup>
19#include <QPainter>
20#include <QHash>
21#include <QApplication>
22#include <QStyle>
23#include <QTimer>
24#include <QMenu>
25#include <QAction>
26#include <QScreen>
27
28#include <klocalizedstring.h>
29#include <WidgetsDebug.h>
30#include <kconfiggroup.h>
31#include <ksharedconfig.h>
32#include <KisPortingUtils.h>
33
34#include <kactioncollection.h>
35#include <KisViewManager.h>
36#include <KoCanvasController.h>
37#include <KoShapeLayer.h>
38
39#define BUTTON_MARGIN 10
40
41static int buttonSize(int screen)
42{
43 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(screen < QGuiApplication::screens().size() && screen >= 0, 16);
44
45 QRect rc = QGuiApplication::screens().at(screen)->availableGeometry();
46 if (rc.width() <= 1024) {
47 return 12;
48 }
49 else if (rc.width() <= 1377) {
50 return 14;
51 }
52 else if (rc.width() <= 1920 ) {
53 return 16;
54 }
55 else {
56 return 22;
57 }
58
59}
60
62{
63public:
64 void addSection(Section *section, const QString &name);
65
68 QHash<QString, KoToolBoxButton*> buttonsByToolId;
69 QMap<QString, Section*> sections;
71 QButtonGroup *buttonGroup {0};
72 QHash<QToolButton*, QString> visibilityCodes;
73 bool floating {false};
74 int iconSize {0};
75 QMap<QAction*,int> contextIconSizes;
77 Qt::Orientation orientation {Qt::Vertical};
78};
79
80void KoToolBox::Private::addSection(Section *section, const QString &name)
81{
82 section->setName(name);
83 layout->addSection(section);
84 sections.insert(name, section);
85}
86
88 : d(new Private)
89{
90 d->layout = new KoToolBoxLayout(this);
91 // add defaults
92 d->addSection(new Section(this), "main");
93 d->addSection(new Section(this), "dynamic");
94
95 d->buttonGroup = new QButtonGroup(this);
96
97 // Get screen the widget exists in, but fall back to primary screen if invalid.
98 const int widgetsScreen = KisPortingUtils::getScreenNumberForWidget(QApplication::activeWindow());
99 const int primaryScreen = 0; //In QT, primary screen should always be the first index of QGuiApplication::screens()
100 const int screen = (widgetsScreen >= 0 && widgetsScreen < QGuiApplication::screens().size()) ? widgetsScreen : primaryScreen;
101 const int toolbuttonSize = buttonSize(screen);
102 KConfigGroup cfg = KSharedConfig::openConfig()->group("KoToolBox");
103 d->iconSize = cfg.readEntry("iconSize", toolbuttonSize);
104
105 Q_FOREACH (KoToolAction *toolAction, KoToolManager::instance()->toolActionList()) {
106 addButton(toolAction);
107 }
108
110
111 // Update visibility of buttons
113
114 connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*)),
115 this, SLOT(setActiveTool(KoCanvasController*)));
116 connect(KoToolManager::instance(), SIGNAL(currentLayerChanged(const KoCanvasController*,const KoShapeLayer*)),
117 this, SLOT(setCurrentLayer(const KoCanvasController*,const KoShapeLayer*)));
118 connect(KoToolManager::instance(), SIGNAL(toolCodesSelected(QList<QString>)), this, SLOT(setButtonsVisible(QList<QString>)));
120 SIGNAL(addedTool(KoToolAction*,KoCanvasController*)),
122
123}
124
126{
127 delete d;
128}
129
131{
132 Q_FOREACH (QToolButton *button, d->buttons) {
133 button->setIconSize(QSize(d->iconSize, d->iconSize));
134 }
135
136 Q_FOREACH (Section *section, d->sections.values()) {
138 }
139}
140
141
143{
144 KisKActionCollection *actionCollection = viewManager->actionCollection();
145 Q_FOREACH(KoToolAction *toolAction, KoToolManager::instance()->toolActionList()) {
146 QAction *toolQAction = actionCollection->action(toolAction->id());
147 auto button = d->buttonsByToolId.find(toolAction->id());
148 if (button == d->buttonsByToolId.end()) {
149 qWarning() << "Toolbox is missing button for tool" << toolAction->id();
150 continue;
151 }
152 (*button)->attachAction(toolQAction);
153 }
154}
155
157{
158 KoToolBoxButton *button = new KoToolBoxButton(toolAction, this);
159
160 d->buttons << button;
161
162 QString sectionToBeAddedTo;
163 const QString section = toolAction->section();
164 if (section.contains(qApp->applicationName())) {
165 sectionToBeAddedTo = "main";
166 } else if (section.contains("main")) {
167 sectionToBeAddedTo = "main";
168 } else if (section.contains("dynamic")) {
169 sectionToBeAddedTo = "dynamic";
170 } else {
171 sectionToBeAddedTo = section;
172 }
173
174 Section *sectionWidget = d->sections.value(sectionToBeAddedTo);
175 if (sectionWidget == 0) {
176 sectionWidget = new Section(this);
177 d->addSection(sectionWidget, sectionToBeAddedTo);
178 }
179 sectionWidget->addButton(button, toolAction->priority());
180
181 d->buttonGroup->addButton(button);
182 d->buttonsByToolId.insert(toolAction->id(), button);
183
184 d->visibilityCodes.insert(button, toolAction->visibilityCode());
185}
186
188{
189 Q_UNUSED(canvas);
190
191 QString id = KoToolManager::instance()->activeToolId();
193 if (button) {
194 button->setChecked(true);
195 button->setHighlightColor();
196 if (d->selectedButton) {
198 }
200 }
201 else {
202 warnWidgets << "KoToolBox::setActiveTool(" << id << "): no such button found";
203 }
204}
205
207{
208 Q_FOREACH (QToolButton *button, d->visibilityCodes.keys()) {
209 QString code = d->visibilityCodes.value(button);
210
211 if (code.startsWith(QLatin1String("flake/"))) {
212 continue;
213 }
214
215 if (code.endsWith( QLatin1String( "/always"))) {
216 button->setVisible(true);
217 button->setEnabled(true);
218 }
219 else if (code.isEmpty()) {
220 button->setVisible(true);
221 button->setEnabled( codes.count() != 0 );
222 }
223 else {
224 button->setVisible( codes.contains(code) );
225 }
226 }
227 layout()->invalidate();
228 update();
229}
230
232{
233 Q_UNUSED(canvas);
234 const bool enabled = layer == 0 || (layer->isShapeEditable() && layer->isVisible());
235 foreach (QToolButton *button, d->visibilityCodes.keys()) {
236 if (d->visibilityCodes[button].endsWith( QLatin1String( "/always") ) ) {
237 continue;
238 }
239 button->setEnabled(enabled);
240 }
241}
242
243void KoToolBox::paintEvent(QPaintEvent *)
244{
245 QPainter painter(this);
246
247 const QList<Section*> sections = d->sections.values();
248 QList<Section*>::const_iterator iterator = sections.begin();
249 int halfSpacing = layout()->spacing();
250 if (halfSpacing > 0) {
251 halfSpacing /= 2;
252 }
253 while(iterator != sections.end()) {
254 Section *section = *iterator;
255 QStyleOption styleoption;
256 styleoption.palette = palette();
257
258 if (section->separators() & Section::SeparatorTop) {
259 int y = section->y() - halfSpacing;
260 styleoption.state = QStyle::State_None;
261 styleoption.rect = QRect(section->x(), y-1, section->width(), 2);
262
263 style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &styleoption, &painter);
264 }
265
266 if (section->separators() & Section::SeparatorLeft && section->isLeftToRight()) {
267 int x = section->x() - halfSpacing;
268 styleoption.state = QStyle::State_Horizontal;
269 styleoption.rect = QRect(x-1, section->y(), 2, section->height());
270
271 style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &styleoption, &painter);
272 } else if (section->separators() & Section::SeparatorLeft && section->isRightToLeft()) {
273 int x = section->x() + section->width() + halfSpacing;
274 styleoption.state = QStyle::State_Horizontal;
275 styleoption.rect = QRect(x-1, section->y(), 2, section->height());
276
277 style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &styleoption, &painter);
278 }
279
280 ++iterator;
281 }
282
283 painter.end();
284}
285
286void KoToolBox::changeEvent(QEvent *event)
287{
288 QWidget::changeEvent(event);
289 if (event->type() == QEvent::PaletteChange) {
290 Q_FOREACH (QToolButton *button, d->buttons) {
291 KoToolBoxButton* toolBoxButton = qobject_cast<KoToolBoxButton*>(button);
292 if (toolBoxButton) {
293 toolBoxButton->setHighlightColor();
294 }
295 }
296 }
297}
298
299void KoToolBox::setOrientation(Qt::Orientation orientation)
300{
301 d->orientation = orientation;
302 d->layout->setOrientation(orientation);
303 QTimer::singleShot(0, this, SLOT(update()));
304 Q_FOREACH (Section* section, d->sections) {
305 section->setOrientation(orientation);
306 }
307}
308
310{
311 d->floating = v;
312}
313
315{
316 Q_UNUSED(canvas);
317 addButton(toolAction);
319
320}
321
323{
324 QAction* action = qobject_cast<QAction*>(sender());
325 if (action) {
326 int iconSize = -1;
327 if (action == d->defaultIconSizeAction) {
328 iconSize = buttonSize(KisPortingUtils::getScreenNumberForWidget(QApplication::activeWindow()));
329 QAction *action = d->contextIconSizes.key(iconSize);
330 if (action) {
331 action->setChecked(true);
332 }
333 } else if (d->contextIconSizes.contains(action)) {
334 iconSize = d->contextIconSizes.value(action);
335 }
337
338 KConfigGroup cfg = KSharedConfig::openConfig()->group("KoToolBox");
339 cfg.writeEntry("iconSize", iconSize);
341
343 }
344}
345
347{
348 if (d->contextIconSizes.isEmpty()) {
349 d->defaultIconSizeAction = menu->addAction(i18nc("@item:inmenu Icon size", "Default"),
350 this, SLOT(slotContextIconSize()));
351
352 QActionGroup *sizeGroup = new QActionGroup(menu);
353 QList<int> sizes;
354 sizes << 12 << 14 << 16 << 22 << 32 << 48 << 64; //<< 96 << 128 << 192 << 256;
355 Q_FOREACH (int i, sizes) {
356 QAction *action = menu->addAction(i18n("%1x%2", i, i), this, SLOT(slotContextIconSize()));
357 d->contextIconSizes.insert(action, i);
358 action->setActionGroup(sizeGroup);
359 action->setCheckable(true);
360 if (d->iconSize == i) {
361 action->setChecked(true);
362 }
363 }
364 }
365}
366
368{
369 return d->layout;
370}
371
372#include "moc_KoToolBoxScrollArea_p.cpp"
qreal v
#define BUTTON_MARGIN
Definition KoToolBox.cpp:39
static int buttonSize(int screen)
Definition KoToolBox.cpp:41
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
#define warnWidgets
int iconSize(qreal width, qreal height)
A container for a set of QAction objects.
QAction * action(int index) const
virtual KisKActionCollection * actionCollection() const
virtual bool isShapeEditable(bool recursive=true) const
checks recursively if the shape or one of its parents is not visible or locked
Definition KoShape.cpp:1165
bool isVisible(bool recursive=true) const
Definition KoShape.cpp:979
QString section() const
The section the tool wants to be in.
QString id() const
The id of the tool.
int priority() const
Lower number (higher priority) means coming first in the section.
QString visibilityCode() const
This tool should become visible when we Q_EMIT this string in toolCodesSelected()
void setOrientation(Qt::Orientation orientation)
void addSection(Section *section)
QHash< QString, KoToolBoxButton * > buttonsByToolId
Definition KoToolBox.cpp:68
QHash< QToolButton *, QString > visibilityCodes
Definition KoToolBox.cpp:72
QMap< QAction *, int > contextIconSizes
Definition KoToolBox.cpp:75
KoToolBoxLayout * layout
Definition KoToolBox.cpp:70
QList< QToolButton * > buttons
Definition KoToolBox.cpp:66
Qt::Orientation orientation
Definition KoToolBox.cpp:77
QAction * defaultIconSizeAction
Definition KoToolBox.cpp:76
void addSection(Section *section, const QString &name)
Definition KoToolBox.cpp:80
KoToolBoxButton * selectedButton
Definition KoToolBox.cpp:67
QMap< QString, Section * > sections
Definition KoToolBox.cpp:69
QButtonGroup * buttonGroup
Definition KoToolBox.cpp:71
void setButtonsVisible(const QList< QString > &codes)
void addButton(KoToolAction *toolAction)
void setupIconSizeMenu(QMenu *menu)
~KoToolBox() override
void paintEvent(QPaintEvent *event) override
void setCurrentLayer(const KoCanvasController *canvas, const KoShapeLayer *newLayer)
void setFloating(bool v)
void applyIconSize()
void toolAdded(KoToolAction *toolAction, KoCanvasController *canvas)
add a tool post-initialization. The tool will also be activated.
void setActiveTool(KoCanvasController *canvas)
KoToolBoxLayout * toolBoxLayout() const
void setViewManager(KisViewManager *viewManager)
void changeEvent(QEvent *event) override
void slotContextIconSize()
set the icon size for all the buttons
Private *const d
void setOrientation(Qt::Orientation orientation)
Set the orientation of the layout to orientation.
KoToolBox()
constructor
Definition KoToolBox.cpp:87
QString activeToolId() const
Returns the toolId of the currently active tool.
static KoToolManager * instance()
Return the toolmanager singleton.
void addButton(QAbstractButton *button, int priority)
void setButtonSize(QSize size)
Separators separators() const
void setOrientation(Qt::Orientation orientation)
void setName(const QString &name)
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
QString button(const QWheelEvent &ev)
int getScreenNumberForWidget(const QWidget *w)
rgba palette[MAX_PALETTE]
Definition palette.c:35