File indexing completed on 2024-05-19 04:23:11
0001 /* 0002 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org> 0003 Copyright (c) 2011 Martin Koller <kollix@aon.at> 0004 All rights reserved. 0005 0006 Redistribution and use in source and binary forms, with or without 0007 modification, are permitted provided that the following conditions 0008 are met: 0009 0010 1. Redistributions of source code must retain the above copyright 0011 notice, this list of conditions and the following disclaimer. 0012 2. Redistributions in binary form must reproduce the above copyright 0013 notice, this list of conditions and the following disclaimer in the 0014 documentation and/or other materials provided with the distribution. 0015 0016 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0017 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0018 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0019 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0020 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0021 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0022 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0023 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0025 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0026 */ 0027 0028 0029 #define DEBUG_KP_TOOL_TOOL_BAR 0 0030 0031 0032 #include "widgets/toolbars/kpToolToolBar.h" 0033 0034 #include <QBoxLayout> 0035 #include <QGridLayout> 0036 #include <QButtonGroup> 0037 #include <QKeyEvent> 0038 #include <QToolButton> 0039 #include <QStyleOption> 0040 #include <QStylePainter> 0041 0042 #include <KToggleAction> 0043 0044 #include "kpLogCategories.h" 0045 0046 #include "kpDefs.h" 0047 #include "tools/kpTool.h" 0048 #include "widgets/toolbars/options/kpToolWidgetBrush.h" 0049 #include "widgets/toolbars/options/kpToolWidgetEraserSize.h" 0050 #include "widgets/toolbars/options/kpToolWidgetFillStyle.h" 0051 #include "widgets/toolbars/options/kpToolWidgetLineWidth.h" 0052 #include "widgets/toolbars/options/kpToolWidgetOpaqueOrTransparent.h" 0053 #include "widgets/toolbars/options/kpToolWidgetSpraycanSize.h" 0054 0055 //--------------------------------------------------------------------- 0056 0057 class kpToolButton : public QToolButton 0058 { 0059 public: 0060 kpToolButton (kpTool *tool, QWidget *parent) 0061 : QToolButton (parent), 0062 m_tool (tool) 0063 { 0064 } 0065 0066 kpTool *tool() const { return m_tool; } 0067 0068 protected: 0069 void mouseDoubleClickEvent(QMouseEvent *e) override 0070 { 0071 if (e->button () == Qt::LeftButton && m_tool) { 0072 m_tool->globalDraw (); 0073 } 0074 } 0075 0076 kpTool *m_tool; 0077 }; 0078 0079 //--------------------------------------------------------------------- 0080 0081 kpToolToolBar::kpToolToolBar(const QString &name, int colsOrRows, QMainWindow *parent) 0082 : KToolBar(name, parent, Qt::LeftToolBarArea), 0083 m_vertCols (colsOrRows), 0084 m_buttonGroup (nullptr), 0085 m_baseWidget (nullptr), 0086 m_baseLayout (nullptr), 0087 m_toolLayout (nullptr), 0088 m_previousTool (nullptr), m_currentTool (nullptr) 0089 { 0090 m_baseWidget = new QWidget(this); 0091 0092 m_toolWidgets.append (m_toolWidgetBrush = 0093 new kpToolWidgetBrush (m_baseWidget, QStringLiteral("Tool Widget Brush"))); 0094 m_toolWidgets.append (m_toolWidgetEraserSize = 0095 new kpToolWidgetEraserSize (m_baseWidget, QStringLiteral("Tool Widget Eraser Size"))); 0096 m_toolWidgets.append (m_toolWidgetFillStyle = 0097 new kpToolWidgetFillStyle (m_baseWidget, QStringLiteral("Tool Widget Fill Style"))); 0098 m_toolWidgets.append (m_toolWidgetLineWidth = 0099 new kpToolWidgetLineWidth (m_baseWidget, QStringLiteral("Tool Widget Line Width"))); 0100 m_toolWidgets.append (m_toolWidgetOpaqueOrTransparent = 0101 new kpToolWidgetOpaqueOrTransparent (m_baseWidget, QStringLiteral("Tool Widget Opaque/Transparent"))); 0102 m_toolWidgets.append (m_toolWidgetSpraycanSize = 0103 new kpToolWidgetSpraycanSize (m_baseWidget, QStringLiteral("Tool Widget Spraycan Size"))); 0104 0105 for (auto *w : m_toolWidgets) 0106 { 0107 connect (w, &kpToolWidgetBase::optionSelected, 0108 this, &kpToolToolBar::toolWidgetOptionSelected); 0109 } 0110 0111 adjustToOrientation(orientation()); 0112 connect (this, &kpToolToolBar::orientationChanged, 0113 this, &kpToolToolBar::adjustToOrientation); 0114 0115 m_buttonGroup = new QButtonGroup (this); 0116 connect (m_buttonGroup, &QButtonGroup::idClicked, 0117 this, &kpToolToolBar::slotToolButtonClicked); 0118 0119 hideAllToolWidgets (); 0120 0121 addWidget(m_baseWidget); 0122 0123 connect (this, &kpToolToolBar::iconSizeChanged, 0124 this, &kpToolToolBar::slotIconSizeChanged); 0125 0126 connect (this, &kpToolToolBar::toolButtonStyleChanged, 0127 this, &kpToolToolBar::slotToolButtonStyleChanged); 0128 } 0129 0130 //--------------------------------------------------------------------- 0131 0132 kpToolToolBar::~kpToolToolBar() 0133 { 0134 while ( !m_toolButtons.isEmpty() ) { 0135 delete m_toolButtons.takeFirst(); 0136 } 0137 } 0138 0139 //--------------------------------------------------------------------- 0140 0141 // public 0142 void kpToolToolBar::registerTool (kpTool *tool) 0143 { 0144 for (const auto *b : m_toolButtons) 0145 { 0146 if ( b->tool() == tool ) { // already given 0147 return; 0148 } 0149 } 0150 0151 auto *b = new kpToolButton(tool, m_baseWidget); 0152 0153 b->setToolButtonStyle(toolButtonStyle()); 0154 b->setIconSize(iconSize()); 0155 b->setAutoRaise(true); 0156 0157 // tell layout to make all with equal width (much better when text-below-icon) 0158 b->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); 0159 0160 b->setDefaultAction(tool->action()); 0161 0162 m_buttonGroup->addButton(b); 0163 addButton(b, orientation(), m_toolButtons.count()); 0164 0165 m_toolButtons.append(b); 0166 0167 connect (tool, &kpTool::actionActivated, 0168 this, &kpToolToolBar::slotToolActionActivated); 0169 0170 adjustSizeConstraint(); 0171 } 0172 0173 //--------------------------------------------------------------------- 0174 // public 0175 0176 void kpToolToolBar::unregisterTool(kpTool *tool) 0177 { 0178 for (int i = 0; i < m_toolButtons.count(); i++) 0179 { 0180 if ( m_toolButtons[i]->tool() == tool ) 0181 { 0182 delete m_toolButtons.takeAt(i); 0183 disconnect (tool, &kpTool::actionActivated, 0184 this, &kpToolToolBar::slotToolActionActivated); 0185 return; 0186 } 0187 } 0188 } 0189 0190 //--------------------------------------------------------------------- 0191 // public 0192 0193 kpTool *kpToolToolBar::tool () const 0194 { 0195 return m_currentTool; 0196 } 0197 0198 //--------------------------------------------------------------------- 0199 0200 // public 0201 void kpToolToolBar::selectTool (const kpTool *tool, bool reselectIfSameTool) 0202 { 0203 #if DEBUG_KP_TOOL_TOOL_BAR 0204 qCDebug(kpLogWidgets) << "kpToolToolBar::selectTool (tool=" << tool 0205 << ") currentTool=" << m_currentTool 0206 << endl; 0207 #endif 0208 0209 if (!reselectIfSameTool && tool == m_currentTool) { 0210 return; 0211 } 0212 0213 if (tool) 0214 { 0215 tool->action()->setChecked(true); 0216 slotToolButtonClicked(); 0217 } 0218 else 0219 { 0220 QAbstractButton *b = m_buttonGroup->checkedButton(); 0221 if (b) 0222 { 0223 // HACK: qbuttongroup.html says the following about exclusive 0224 // button groups: 0225 // 0226 // "to untoggle a button you must click on another button 0227 // in the group" 0228 // 0229 // But we don't want any button to be selected. 0230 // So don't be an exclusive button group temporarily. 0231 m_buttonGroup->setExclusive (false); 0232 b->setChecked (false); 0233 m_buttonGroup->setExclusive (true); 0234 0235 slotToolButtonClicked (); 0236 } 0237 } 0238 } 0239 0240 //--------------------------------------------------------------------- 0241 0242 // public 0243 kpTool *kpToolToolBar::previousTool () const 0244 { 0245 return m_previousTool; 0246 } 0247 0248 //--------------------------------------------------------------------- 0249 0250 // public 0251 void kpToolToolBar::selectPreviousTool () 0252 { 0253 selectTool (m_previousTool); 0254 } 0255 0256 //--------------------------------------------------------------------- 0257 0258 // public 0259 void kpToolToolBar::hideAllToolWidgets () 0260 { 0261 for (auto *w : m_toolWidgets) { 0262 w->hide (); 0263 } 0264 } 0265 0266 //--------------------------------------------------------------------- 0267 0268 // public 0269 kpToolWidgetBase *kpToolToolBar::shownToolWidget (int which) const 0270 { 0271 int uptoVisibleWidget = 0; 0272 0273 for(auto *w : m_toolWidgets) 0274 { 0275 if ( !w->isHidden() ) 0276 { 0277 if (which == uptoVisibleWidget) { 0278 return w; 0279 } 0280 0281 uptoVisibleWidget++; 0282 } 0283 } 0284 0285 return nullptr; 0286 } 0287 0288 //--------------------------------------------------------------------- 0289 0290 // private slot 0291 void kpToolToolBar::slotToolButtonClicked () 0292 { 0293 QAbstractButton *b = m_buttonGroup->checkedButton(); 0294 0295 #if DEBUG_KP_TOOL_TOOL_BAR 0296 qCDebug(kpLogWidgets) << "kpToolToolBar::slotToolButtonClicked() button=" << b; 0297 #endif 0298 0299 kpTool *tool = nullptr; 0300 for (const auto *button : m_toolButtons) 0301 { 0302 if ( button == b ) 0303 { 0304 tool = button->tool(); 0305 break; 0306 } 0307 } 0308 0309 #if DEBUG_KP_TOOL_TOOL_BAR 0310 qCDebug(kpLogWidgets) << "\ttool=" << tool 0311 << " currentTool=" << m_currentTool 0312 << endl; 0313 #endif 0314 0315 if (tool == m_currentTool) 0316 { 0317 if (m_currentTool) { 0318 m_currentTool->reselect (); 0319 } 0320 0321 return; 0322 } 0323 0324 if (m_currentTool) { 0325 m_currentTool->endInternal (); 0326 } 0327 0328 m_previousTool = m_currentTool; 0329 m_currentTool = tool; 0330 0331 if (m_currentTool) 0332 { 0333 KToggleAction *action = m_currentTool->action (); 0334 if (action) 0335 { 0336 action->setChecked (true); 0337 } 0338 0339 m_currentTool->beginInternal (); 0340 } 0341 0342 Q_EMIT sigToolSelected (m_currentTool); 0343 m_baseLayout->activate(); 0344 adjustSizeConstraint(); 0345 } 0346 0347 //--------------------------------------------------------------------- 0348 0349 // private slot 0350 void kpToolToolBar::slotToolActionActivated () 0351 { 0352 const auto *tool = dynamic_cast<const kpTool *>(sender()); 0353 0354 #if DEBUG_KP_TOOL_TOOL_BAR 0355 qCDebug(kpLogWidgets) << "kpToolToolBar::slotToolActionActivated() tool=" 0356 << (tool ? tool->objectName () : "null") 0357 << endl; 0358 #endif 0359 0360 selectTool (tool, true/*reselect if same tool*/); 0361 } 0362 0363 //--------------------------------------------------------------------- 0364 0365 // public 0366 void kpToolToolBar::adjustToOrientation(Qt::Orientation o) 0367 { 0368 #if DEBUG_KP_TOOL_TOOL_BAR 0369 qCDebug(kpLogWidgets) << "kpToolToolBar::adjustToOrientation(" 0370 << (o == Qt::Vertical ? "vertical" : "horizontal") 0371 << ") called!" << endl; 0372 #endif 0373 0374 delete m_baseLayout; 0375 if (o == Qt::Vertical) 0376 { 0377 m_baseLayout = new QBoxLayout (QBoxLayout::TopToBottom, m_baseWidget); 0378 } 0379 else // if (o == Qt::Horizontal) 0380 { 0381 m_baseLayout = new QBoxLayout (QBoxLayout::LeftToRight, m_baseWidget); 0382 } 0383 m_baseLayout->setSizeConstraint(QLayout::SetFixedSize); 0384 m_baseLayout->setContentsMargins(0, 0, 0, 0); 0385 0386 m_toolLayout = new QGridLayout(); 0387 m_toolLayout->setContentsMargins(0, 0, 0, 0); 0388 0389 // (ownership is transferred to m_baseLayout) 0390 m_baseLayout->addItem (m_toolLayout); 0391 0392 auto num = 0; 0393 0394 for (auto *b : m_toolButtons) 0395 { 0396 addButton(b, o, num); 0397 num++; 0398 } 0399 0400 for (auto *w : m_toolWidgets) 0401 { 0402 m_baseLayout->addWidget(w, 0403 0/*stretch*/, 0404 o == Qt::Vertical ? Qt::AlignHCenter : Qt::AlignVCenter); 0405 } 0406 0407 adjustSizeConstraint(); 0408 } 0409 0410 0411 bool kpToolToolBar::event(QEvent *ev) 0412 { 0413 if (ev->type() == QEvent::LayoutRequest) { 0414 adjustSizeConstraint(); 0415 } 0416 return KToolBar::event(ev); 0417 } 0418 0419 void kpToolToolBar::paintEvent(class QPaintEvent *) 0420 { 0421 QStyleOption opt; 0422 opt.initFrom(this); 0423 if (opt.rect.height() <= contentsMargins().top() + contentsMargins().bottom() || opt.rect.width() <= contentsMargins().left() + contentsMargins().right()) { 0424 return; 0425 } 0426 0427 QStylePainter painter(this); 0428 0429 opt.rect.setX(opt.rect.width() - style()->pixelMetric(QStyle::PM_SplitterWidth)); 0430 opt.rect.setWidth(style()->pixelMetric(QStyle::PM_SplitterWidth)); 0431 opt.state = QStyle::State_Horizontal; 0432 0433 painter.drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, opt); 0434 } 0435 0436 //--------------------------------------------------------------------- 0437 // this makes the size handled correctly during dragging/undocking the toolbar 0438 0439 void kpToolToolBar::adjustSizeConstraint() 0440 { 0441 // remove constraints 0442 setFixedSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); 0443 0444 if ( orientation() == Qt::Vertical ) 0445 { 0446 setFixedWidth(m_baseLayout->sizeHint().width() + 0447 layout()->contentsMargins().left() + 0448 layout()->contentsMargins().right()); 0449 } 0450 else 0451 { 0452 setFixedHeight(m_baseLayout->sizeHint().height() + 0453 layout()->contentsMargins().top() + 0454 layout()->contentsMargins().bottom()); 0455 } 0456 } 0457 0458 //--------------------------------------------------------------------- 0459 0460 // private 0461 void kpToolToolBar::addButton(QAbstractButton *button, Qt::Orientation o, int num) 0462 { 0463 if (o == Qt::Vertical) { 0464 m_toolLayout->addWidget (button, num / m_vertCols, num % m_vertCols); 0465 } 0466 else 0467 { 0468 // maps Left (o = vertical) to Bottom (o = horizontal) 0469 int row = (m_vertCols - 1) - (num % m_vertCols); 0470 m_toolLayout->addWidget (button, row, num / m_vertCols); 0471 } 0472 } 0473 0474 //--------------------------------------------------------------------- 0475 0476 void kpToolToolBar::slotIconSizeChanged(const QSize &size) 0477 { 0478 for (auto *b : m_toolButtons) { 0479 b->setIconSize(size); 0480 } 0481 0482 m_baseLayout->activate(); 0483 adjustSizeConstraint(); 0484 } 0485 0486 //--------------------------------------------------------------------- 0487 0488 void kpToolToolBar::slotToolButtonStyleChanged(Qt::ToolButtonStyle style) 0489 { 0490 for (auto *b : m_toolButtons) { 0491 b->setToolButtonStyle(style); 0492 } 0493 0494 m_baseLayout->activate(); 0495 adjustSizeConstraint(); 0496 } 0497 0498 //--------------------------------------------------------------------- 0499 0500 #include "moc_kpToolToolBar.cpp"