Warning, file /sdk/ktechlab/src/canvasitemparts.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "canvasitemparts.h" 0012 #include "cells.h" 0013 #include "cnitem.h" 0014 #include "icndocument.h" 0015 0016 #include <QPainter> 0017 #include <QWheelEvent> 0018 #include <QStyle> 0019 #include <QStyleOptionSlider> 0020 #include <QStyleOptionToolButton> 0021 0022 #include <ktechlab_debug.h> 0023 0024 // BEGIN Class GuiPart 0025 GuiPart::GuiPart(CNItem *parent, const QRect &r, KtlQCanvas *canvas) 0026 : // QObject(parent), 0027 KtlQCanvasRectangle(r, canvas) 0028 , m_angleDegrees(0) 0029 , p_parent(parent) 0030 , b_pointsAdded(false) 0031 , m_originalRect(r) 0032 { 0033 connect(parent, &CNItem::movedBy, this, &GuiPart::slotMoveBy); 0034 setZ(parent->z() + 0.5); 0035 } 0036 0037 GuiPart::~GuiPart() 0038 { 0039 hide(); 0040 } 0041 0042 void GuiPart::setAngleDegrees(int angleDegrees) 0043 { 0044 m_angleDegrees = angleDegrees; 0045 posChanged(); 0046 if (canvas()) 0047 canvas()->setChanged(boundingRect()); 0048 } 0049 0050 void GuiPart::setGuiPartSize(int width, int height) 0051 { 0052 updateConnectorPoints(false); 0053 setSize(width, height); 0054 posChanged(); 0055 } 0056 0057 void GuiPart::initPainter(QPainter &p) 0058 { 0059 if ((m_angleDegrees % 180) == 0) 0060 return; 0061 0062 p.translate(int(x() + (width() / 2)), int(y() + (height() / 2))); 0063 p.rotate(m_angleDegrees); 0064 p.translate(-int(x() + (width() / 2)), -int(y() + (height() / 2))); 0065 } 0066 0067 void GuiPart::deinitPainter(QPainter &p) 0068 { 0069 if ((m_angleDegrees % 180) == 0) 0070 return; 0071 0072 p.translate(int(x() + (width() / 2)), int(y() + (height() / 2))); 0073 p.rotate(-m_angleDegrees); 0074 p.translate(-int(x() + (width() / 2)), -int(y() + (height() / 2))); 0075 } 0076 0077 void GuiPart::slotMoveBy(double dx, double dy) 0078 { 0079 if (dx == 0 && dy == 0) 0080 return; 0081 0082 moveBy(dx, dy); 0083 posChanged(); 0084 } 0085 0086 void GuiPart::updateConnectorPoints(bool add) 0087 { 0088 ICNDocument *icnd = dynamic_cast<ICNDocument *>(p_parent->itemDocument()); 0089 if (!icnd) 0090 return; 0091 0092 Cells *cells = icnd->cells(); 0093 if (!cells) 0094 return; 0095 0096 if (!isVisible()) 0097 add = false; 0098 0099 if (add == b_pointsAdded) 0100 return; 0101 0102 b_pointsAdded = add; 0103 0104 int mult = add ? 1 : -1; 0105 int sx = roundDown(x(), 8); 0106 int sy = roundDown(y(), 8); 0107 int ex = roundDown(x() + width(), 8); 0108 int ey = roundDown(y() + height(), 8); 0109 0110 for (int x = sx; x <= ex; ++x) { 0111 for (int y = sy; y <= ey; ++y) { 0112 if (cells->haveCell(x, y)) 0113 cells->cell(x, y).CIpenalty += mult * ICNDocument::hs_item / 2; 0114 } 0115 } 0116 } 0117 0118 QRect GuiPart::drawRect() 0119 { 0120 QRect dr = rect(); 0121 if (m_angleDegrees % 180 != 0) { 0122 QTransform m; 0123 m.translate(int(x() + (width() / 2)), int(y() + (height() / 2))); 0124 0125 if ((m_angleDegrees % 180) != 0) 0126 m.rotate(-m_angleDegrees); 0127 0128 m.translate(-int(x() + (width() / 2)), -int(y() + (height() / 2))); 0129 0130 dr = m.mapRect(dr); 0131 } 0132 return dr; 0133 } 0134 // END Class GuiPart 0135 0136 // BEGIN Class Text 0137 Text::Text(const QString &text, CNItem *parent, const QRect &r, KtlQCanvas *canvas, int flags) 0138 : GuiPart(parent, r, canvas) 0139 { 0140 m_flags = flags; 0141 setText(text); 0142 } 0143 0144 Text::~Text() 0145 { 0146 } 0147 0148 bool Text::setText(const QString &text) 0149 { 0150 if (m_text == text) 0151 return false; 0152 0153 updateConnectorPoints(false); 0154 0155 m_text = text; 0156 return true; 0157 } 0158 0159 void Text::setFlags(int flags) 0160 { 0161 updateConnectorPoints(false); 0162 m_flags = flags; 0163 } 0164 0165 void Text::drawShape(QPainter &p) 0166 { 0167 initPainter(p); 0168 p.setFont(p_parent->font()); 0169 p.drawText(drawRect(), m_flags, m_text); 0170 deinitPainter(p); 0171 } 0172 0173 QRect Text::recommendedRect() const 0174 { 0175 return QFontMetrics(p_parent->font()).boundingRect(m_originalRect.x(), m_originalRect.y(), m_originalRect.width(), m_originalRect.height(), m_flags, m_text); 0176 } 0177 // END Class Text 0178 0179 // BEGIN Class Widget 0180 Widget::Widget(const QString &id, CNItem *parent, const QRect &r, KtlQCanvas *canvas) 0181 : GuiPart(parent, r, canvas) 0182 { 0183 m_id = id; 0184 show(); 0185 } 0186 0187 Widget::~Widget() 0188 { 0189 } 0190 0191 void Widget::setEnabled(bool enabled) 0192 { 0193 widget()->setEnabled(enabled); 0194 } 0195 0196 void Widget::posChanged() 0197 { 0198 // Swap around the width / height if we are rotated at a non-half way around 0199 if (m_angleDegrees % 90 != 0) 0200 widget()->setFixedSize(QSize(height(), width())); 0201 else 0202 widget()->setFixedSize(size()); 0203 0204 widget()->move(int(x()), int(y())); 0205 } 0206 0207 void Widget::drawShape(QPainter &p) 0208 { 0209 widget()->render(&p, QPoint(x(), y())); 0210 } 0211 // END Class Widget 0212 0213 // BEGIN Class ToolButton 0214 ToolButton::ToolButton(QWidget *parent) 0215 : QToolButton(parent) 0216 { 0217 m_angleDegrees = 0; 0218 if (QFontInfo(m_font).pixelSize() > 11) // It has to be > 11, not > 12, as (I think) pixelSize() rounds off the actual size 0219 m_font.setPixelSize(12); 0220 } 0221 0222 void ToolButton::drawButtonLabel(QPainter *p) 0223 { 0224 if (m_angleDegrees % 180 == 0 || text().isEmpty()) { 0225 // QToolButton::drawButtonLabel(p); 0226 QToolButton::render(p); 0227 return; 0228 } 0229 0230 double dx = size().width() / 2; 0231 double dy = size().height() / 2; 0232 0233 p->translate(dx, dy); 0234 p->rotate(m_angleDegrees); 0235 p->translate(-dx, -dy); 0236 0237 p->translate(-dy + dx, 0); 0238 0239 int m = width() > height() ? width() : height(); 0240 0241 p->setPen(Qt::black); 0242 p->drawText(isDown() ? 1 : 0, isDown() ? 1 : 0, m, m, Qt::AlignVCenter | Qt::AlignHCenter, text()); 0243 0244 p->translate(dy - dx, 0); 0245 0246 p->translate(dx, dy); 0247 p->rotate(-m_angleDegrees); 0248 p->translate(-dx, -dy); 0249 } 0250 // END Class ToolButton 0251 0252 // BEGIN Class Button 0253 Button::Button(const QString &id, CNItem *parent, bool isToggle, const QRect &r, KtlQCanvas *canvas) 0254 : Widget(id, parent, r, canvas) 0255 { 0256 b_isToggle = isToggle; 0257 m_button = new ToolButton(nullptr); 0258 m_button->setToolButtonStyle(Qt::ToolButtonIconOnly); 0259 m_button->setCheckable(b_isToggle); 0260 connect(m_button, &ToolButton::pressed, this, &Button::slotStateChanged); 0261 connect(m_button, &ToolButton::released, this, &Button::slotStateChanged); 0262 posChanged(); 0263 } 0264 0265 Button::~Button() 0266 { 0267 delete m_button; 0268 } 0269 0270 void Button::drawShape(QPainter &p) 0271 { 0272 const QTransform transform = p.worldTransform(); 0273 p.setTransform(QTransform()); 0274 0275 QStyleOptionToolButton opt; 0276 opt.initFrom(m_button); 0277 m_button->initStyleOpt(&opt); 0278 0279 opt.rect.translate(x(), y()); 0280 opt.rect = transform.mapRect(opt.rect); 0281 0282 m_button->style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &p, m_button); 0283 0284 p.setTransform(transform); 0285 } 0286 0287 void Button::setToggle(bool toggle) 0288 { 0289 if (b_isToggle == toggle) 0290 return; 0291 0292 if (b_isToggle) { 0293 // We must first untoggle it, else it'll be forever stuck... 0294 setState(false); 0295 } 0296 0297 b_isToggle = toggle; 0298 m_button->setCheckable(b_isToggle); 0299 } 0300 0301 void Button::posChanged() 0302 { 0303 Widget::posChanged(); 0304 m_button->setAngleDegrees(m_angleDegrees); 0305 } 0306 0307 void Button::slotStateChanged() 0308 { 0309 parent()->buttonStateChanged(id(), m_button->isDown() || m_button->isChecked()); 0310 } 0311 QWidget *Button::widget() const 0312 { 0313 return m_button; 0314 } 0315 void Button::setIcon(const QIcon &icon) 0316 { 0317 m_button->setIcon(icon); 0318 } 0319 void Button::setState(bool state) 0320 { 0321 if (this->state() == state) 0322 return; 0323 0324 if (isToggle()) 0325 m_button->setChecked(state); 0326 else 0327 m_button->setDown(state); 0328 0329 slotStateChanged(); 0330 } 0331 bool Button::state() const 0332 { 0333 if (isToggle()) 0334 return m_button->isChecked(); // was: state() 0335 else 0336 return m_button->isDown(); 0337 } 0338 0339 QRect Button::recommendedRect() const 0340 { 0341 QSize sizeHint = m_button->sizeHint(); 0342 if (sizeHint.width() < m_originalRect.width()) 0343 sizeHint.setWidth(m_originalRect.width()); 0344 0345 // Hmm...for now, lets just keep the recomended rect the same height as the original rect 0346 sizeHint.setHeight(m_originalRect.height()); 0347 0348 int hdw = (sizeHint.width() - m_originalRect.width()) / 2; 0349 int hdh = (sizeHint.height() - m_originalRect.height()) / 2; 0350 0351 return QRect(m_originalRect.x() - hdw, m_originalRect.y() - hdh, sizeHint.width(), sizeHint.height()); 0352 } 0353 0354 void Button::setText(const QString &text) 0355 { 0356 if (m_button->text() == text) 0357 return; 0358 0359 updateConnectorPoints(false); 0360 0361 m_button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); 0362 m_button->setText(text); 0363 m_button->setToolTip(text); 0364 canvas()->setChanged(rect()); 0365 p_parent->updateAttachedPositioning(); 0366 } 0367 0368 void Button::mousePressEvent(QMouseEvent *e) 0369 { 0370 if (!m_button->isEnabled()) 0371 return; 0372 0373 QMouseEvent event(QEvent::MouseButtonPress, 0374 e->pos() - QPoint(int(x()), int(y())), 0375 e->button(), 0376 // e->state() // 2018.12.02 0377 e->buttons(), 0378 e->modifiers()); 0379 m_button->mousePressEvent(&event); 0380 if (event.isAccepted()) 0381 e->accept(); 0382 canvas()->setChanged(rect()); 0383 } 0384 0385 void Button::mouseReleaseEvent(QMouseEvent *e) 0386 { 0387 QMouseEvent event(QEvent::MouseButtonRelease, 0388 e->pos() - QPoint(int(x()), int(y())), 0389 e->button(), 0390 // e->state() 0391 e->buttons(), 0392 e->modifiers()); 0393 m_button->mouseReleaseEvent(&event); 0394 if (event.isAccepted()) 0395 e->accept(); 0396 canvas()->setChanged(rect()); 0397 } 0398 0399 void Button::enterEvent(QEvent *) 0400 { 0401 m_button->enterEvent(nullptr); 0402 // m_button->setFocus(); 0403 // bool hasFocus = m_button->hasFocus(); 0404 // m_button->setAutoRaise(true); 0405 // m_button->setChecked(true); 0406 } 0407 0408 void Button::leaveEvent(QEvent *) 0409 { 0410 m_button->leaveEvent(nullptr); 0411 // m_button->clearFocus(); 0412 // bool hasFocus = m_button->hasFocus(); 0413 // m_button->setAutoRaise(false); 0414 // m_button->setChecked(false); 0415 } 0416 // END Class Button 0417 0418 // BEGIN Class SliderWidget 0419 SliderWidget::SliderWidget(QWidget *parent) 0420 : QSlider(parent) 0421 { 0422 // setWFlags(Qt::WNoAutoErase|Qt::WRepaintNoErase); 0423 // setWindowFlags(/*Qt::WNoAutoErase | */ Qt::WRepaintNoErase); 0424 } 0425 // END Class SliderWidget 0426 0427 // BEGIN Class Slider 0428 Slider::Slider(const QString &id, CNItem *parent, const QRect &r, KtlQCanvas *canvas) 0429 : Widget(id, parent, r, canvas) 0430 { 0431 m_orientation = Qt::Vertical; 0432 m_bSliderInverted = false; 0433 0434 m_slider = new SliderWidget(nullptr); 0435 QPalette p; 0436 p.setColor(m_slider->backgroundRole(), Qt::white); 0437 m_slider->setPalette(p); 0438 connect(m_slider, &SliderWidget::valueChanged, this, &Slider::slotValueChanged); 0439 posChanged(); 0440 } 0441 0442 Slider::~Slider() 0443 { 0444 delete m_slider; 0445 } 0446 0447 QWidget *Slider::widget() const 0448 { 0449 return m_slider; 0450 } 0451 0452 int Slider::value() const 0453 { 0454 if (m_bSliderInverted) { 0455 // Return the value as if the slider handle was reflected along through 0456 // the center of the slide. 0457 return m_slider->maximum() + m_slider->minimum() - m_slider->value(); 0458 } else 0459 return m_slider->value(); 0460 } 0461 0462 void Slider::setValue(int value) 0463 { 0464 if (m_bSliderInverted) { 0465 value = m_slider->maximum() + m_slider->minimum() - value; 0466 } 0467 0468 m_slider->setValue(value); 0469 0470 if (canvas()) 0471 canvas()->setChanged(rect()); 0472 } 0473 0474 void Slider::mousePressEvent(QMouseEvent *e) 0475 { 0476 qCDebug(KTL_LOG) << "pos " << e->pos() << " x " << int(x()) << " y " << int(y()) << " b " << e->button() << " bs " << e->buttons() << " m " << e->modifiers(); 0477 QMouseEvent event(QEvent::MouseButtonPress, e->pos() - QPoint(int(x()), int(y())), e->button(), e->buttons(), e->modifiers() // e->state() // 2018.12.02 0478 ); 0479 m_slider->mousePressEvent(&event); 0480 if (event.isAccepted()) { 0481 qCDebug(KTL_LOG) << "accepted " << e; 0482 e->accept(); 0483 } 0484 canvas()->setChanged(rect()); 0485 } 0486 0487 void Slider::mouseReleaseEvent(QMouseEvent *e) 0488 { 0489 qCDebug(KTL_LOG) << "pos " << e->pos() << " x " << int(x()) << " y " << int(y()) << " b " << e->button() << " bs " << e->buttons() << " m " << e->modifiers(); 0490 QMouseEvent event(QEvent::MouseButtonRelease, e->pos() - QPoint(int(x()), int(y())), e->button(), e->buttons(), e->modifiers() // e->state() // 2018.12.02 0491 ); 0492 m_slider->mouseReleaseEvent(&event); 0493 if (event.isAccepted()) { 0494 qCDebug(KTL_LOG) << "accepted " << e; 0495 e->accept(); 0496 } 0497 canvas()->setChanged(rect()); 0498 } 0499 0500 void Slider::mouseDoubleClickEvent(QMouseEvent *e) 0501 { 0502 QMouseEvent event(QEvent::MouseButtonDblClick, e->pos() - QPoint(int(x()), int(y())), e->button(), e->buttons(), e->modifiers() // e->state() // 2018.12.02 0503 ); 0504 m_slider->mouseDoubleClickEvent(&event); 0505 if (event.isAccepted()) 0506 e->accept(); 0507 canvas()->setChanged(rect()); 0508 } 0509 0510 void Slider::mouseMoveEvent(QMouseEvent *e) 0511 { 0512 QMouseEvent event(QEvent::MouseMove, e->pos() - QPoint(int(x()), int(y())), e->button(), e->buttons(), e->modifiers() // e->state() //2018.12.02 0513 ); 0514 m_slider->mouseMoveEvent(&event); 0515 if (event.isAccepted()) 0516 e->accept(); 0517 } 0518 0519 void Slider::wheelEvent(QWheelEvent *e) 0520 { 0521 QWheelEvent event(e->pos() - QPoint(int(x()), int(y())), 0522 e->delta(), 0523 e->buttons(), 0524 e->modifiers(), // e->state(), 0525 e->orientation()); 0526 m_slider->wheelEvent(&event); 0527 if (event.isAccepted()) 0528 e->accept(); 0529 canvas()->setChanged(rect()); 0530 } 0531 0532 void Slider::enterEvent(QEvent *e) 0533 { 0534 qCDebug(KTL_LOG); 0535 m_slider->enterEvent(e); 0536 } 0537 0538 void Slider::leaveEvent(QEvent *e) 0539 { 0540 qCDebug(KTL_LOG); 0541 m_slider->leaveEvent(e); 0542 } 0543 0544 void Slider::slotValueChanged(int value) 0545 { 0546 if (parent()->itemDocument()) 0547 parent()->itemDocument()->setModified(true); 0548 0549 // Note that we do not use value as we want to take into account rotation 0550 (void)value; 0551 parent()->sliderValueChanged(id(), this->value()); 0552 0553 if (canvas()) 0554 canvas()->setChanged(rect()); 0555 } 0556 0557 void Slider::setOrientation(Qt::Orientation o) 0558 { 0559 m_orientation = o; 0560 posChanged(); 0561 } 0562 0563 void Slider::drawShape(QPainter &p) 0564 { 0565 QStyleOptionSlider opt; 0566 opt.initFrom(m_slider); 0567 m_slider->initStyleOpt(&opt); 0568 opt.subControls = QStyle::SC_All; 0569 0570 opt.rect.translate(x(), y()); 0571 opt.rect = p.worldTransform().mapRect(opt.rect); 0572 0573 p.setWorldMatrixEnabled(false); 0574 m_slider->style()->drawComplexControl(QStyle::CC_Slider, &opt, &p, m_slider); 0575 p.setWorldMatrixEnabled(true); 0576 0577 } 0578 0579 void Slider::posChanged() 0580 { 0581 Widget::posChanged(); 0582 0583 bool nowInverted; 0584 0585 if (m_orientation == Qt::Vertical) { 0586 nowInverted = angleDegrees() == 90 || angleDegrees() == 180; 0587 m_slider->setOrientation((m_angleDegrees % 180 == 0) ? Qt::Vertical : Qt::Horizontal); 0588 } 0589 0590 else { 0591 nowInverted = angleDegrees() == 0 || angleDegrees() == 90; 0592 m_slider->setOrientation((m_angleDegrees % 180 == 0) ? Qt::Horizontal : Qt::Vertical); 0593 } 0594 0595 if (m_slider->orientation() == Qt::Vertical) { 0596 m_slider->setFixedWidth(m_slider->sizeHint().width()); 0597 m_slider->setFixedHeight(height()); 0598 } else { 0599 m_slider->setFixedWidth(width()); 0600 m_slider->setFixedHeight(m_slider->sizeHint().height()); 0601 } 0602 0603 if (nowInverted != m_bSliderInverted) { 0604 int prevValue = value(); 0605 m_bSliderInverted = nowInverted; 0606 setValue(prevValue); 0607 } 0608 } 0609 // END Class Slider