diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch) | |
tree | 67208f7c145782a7e90b123b982ca78d88cc2c87 /kalarm/lib/spinbox2.cpp | |
download | tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kalarm/lib/spinbox2.cpp')
-rw-r--r-- | kalarm/lib/spinbox2.cpp | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/kalarm/lib/spinbox2.cpp b/kalarm/lib/spinbox2.cpp new file mode 100644 index 000000000..313d3eb56 --- /dev/null +++ b/kalarm/lib/spinbox2.cpp @@ -0,0 +1,511 @@ +/* + * spinbox2.cpp - spin box with extra pair of spin buttons (for Qt 3) + * Program: kalarm + * Copyright © 2001-2005,2008 by David Jarvie <djarvie@kde.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qglobal.h> + +#include <stdlib.h> + +#include <qstyle.h> +#include <qobjectlist.h> +#include <qapplication.h> +#include <qpixmap.h> +#include <qcursor.h> +#include <qtimer.h> +#include <qwmatrix.h> + +#include "spinbox2.moc" +#include "spinbox2private.moc" + + +/* List of styles which need to display the extra pair of spin buttons as a + * left-to-right mirror image. This is only necessary when, for example, the + * corners of widgets are rounded. For most styles, it is better not to mirror + * the spin widgets so as to keep the normal lighting/shading on either side. + */ +static const char* mirrorStyles[] = { + "PlastikStyle", + 0 // list terminator +}; +static bool mirrorStyle(const QStyle&); + + +int SpinBox2::mReverseLayout = -1; + +SpinBox2::SpinBox2(QWidget* parent, const char* name) + : QFrame(parent, name), + mReverseWithLayout(true) +{ + mUpdown2Frame = new QFrame(this); + mSpinboxFrame = new QFrame(this); + mUpdown2 = new ExtraSpinBox(mUpdown2Frame, "updown2"); +// mSpinbox = new MainSpinBox(0, 1, 1, this, mSpinboxFrame); + mSpinbox = new MainSpinBox(this, mSpinboxFrame); + init(); +} + +SpinBox2::SpinBox2(int minValue, int maxValue, int step, int step2, QWidget* parent, const char* name) + : QFrame(parent, name), + mReverseWithLayout(true) +{ + mUpdown2Frame = new QFrame(this); + mSpinboxFrame = new QFrame(this); + mUpdown2 = new ExtraSpinBox(minValue, maxValue, step2, mUpdown2Frame, "updown2"); + mSpinbox = new MainSpinBox(minValue, maxValue, step, this, mSpinboxFrame); + setSteps(step, step2); + init(); +} + +void SpinBox2::init() +{ + if (mReverseLayout < 0) + mReverseLayout = QApplication::reverseLayout() ? 1 : 0; + mMinValue = mSpinbox->minValue(); + mMaxValue = mSpinbox->maxValue(); + mLineStep = mSpinbox->lineStep(); + mLineShiftStep = mSpinbox->lineShiftStep(); + mPageStep = mUpdown2->lineStep(); + mPageShiftStep = mUpdown2->lineShiftStep(); + mSpinbox->setSelectOnStep(false); // default + mUpdown2->setSelectOnStep(false); // always false + setFocusProxy(mSpinbox); + mUpdown2->setFocusPolicy(QWidget::NoFocus); + mSpinMirror = new SpinMirror(mUpdown2, mUpdown2Frame, this); + if (!mirrorStyle(style())) + mSpinMirror->hide(); // hide mirrored spin buttons when they are inappropriate + connect(mSpinbox, SIGNAL(valueChanged(int)), SLOT(valueChange())); + connect(mSpinbox, SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int))); + connect(mSpinbox, SIGNAL(valueChanged(const QString&)), SIGNAL(valueChanged(const QString&))); + connect(mUpdown2, SIGNAL(stepped(int)), SLOT(stepPage(int))); + connect(mUpdown2, SIGNAL(styleUpdated()), SLOT(updateMirror())); +} + +void SpinBox2::setReadOnly(bool ro) +{ + if (static_cast<int>(ro) != static_cast<int>(mSpinbox->isReadOnly())) + { + mSpinbox->setReadOnly(ro); + mUpdown2->setReadOnly(ro); + mSpinMirror->setReadOnly(ro); + } +} + +void SpinBox2::setReverseWithLayout(bool reverse) +{ + if (reverse != mReverseWithLayout) + { + mReverseWithLayout = reverse; + setSteps(mLineStep, mPageStep); + setShiftSteps(mLineShiftStep, mPageShiftStep); + } +} + +void SpinBox2::setEnabled(bool enabled) +{ + QFrame::setEnabled(enabled); + updateMirror(); +} + +void SpinBox2::setWrapping(bool on) +{ + mSpinbox->setWrapping(on); + mUpdown2->setWrapping(on); +} + +QRect SpinBox2::up2Rect() const +{ + return mUpdown2->upRect(); +} + +QRect SpinBox2::down2Rect() const +{ + return mUpdown2->downRect(); +} + +void SpinBox2::setLineStep(int step) +{ + mLineStep = step; + if (reverseButtons()) + mUpdown2->setLineStep(step); // reverse layout, but still set the right buttons + else + mSpinbox->setLineStep(step); +} + +void SpinBox2::setSteps(int line, int page) +{ + mLineStep = line; + mPageStep = page; + if (reverseButtons()) + { + mUpdown2->setLineStep(line); // reverse layout, but still set the right buttons + mSpinbox->setLineStep(page); + } + else + { + mSpinbox->setLineStep(line); + mUpdown2->setLineStep(page); + } +} + +void SpinBox2::setShiftSteps(int line, int page) +{ + mLineShiftStep = line; + mPageShiftStep = page; + if (reverseButtons()) + { + mUpdown2->setLineShiftStep(line); // reverse layout, but still set the right buttons + mSpinbox->setLineShiftStep(page); + } + else + { + mSpinbox->setLineShiftStep(line); + mUpdown2->setLineShiftStep(page); + } +} + +void SpinBox2::setButtonSymbols(QSpinBox::ButtonSymbols newSymbols) +{ + if (mSpinbox->buttonSymbols() == newSymbols) + return; + mSpinbox->setButtonSymbols(newSymbols); + mUpdown2->setButtonSymbols(newSymbols); +} + +int SpinBox2::bound(int val) const +{ + return (val < mMinValue) ? mMinValue : (val > mMaxValue) ? mMaxValue : val; +} + +void SpinBox2::setMinValue(int val) +{ + mMinValue = val; + mSpinbox->setMinValue(val); + mUpdown2->setMinValue(val); +} + +void SpinBox2::setMaxValue(int val) +{ + mMaxValue = val; + mSpinbox->setMaxValue(val); + mUpdown2->setMaxValue(val); +} + +void SpinBox2::valueChange() +{ + int val = mSpinbox->value(); + bool blocked = mUpdown2->signalsBlocked(); + mUpdown2->blockSignals(true); + mUpdown2->setValue(val); + mUpdown2->blockSignals(blocked); +} + +/****************************************************************************** +* Called when the widget is about to be displayed. +* (At construction time, the spin button widths cannot be determined correctly, +* so we need to wait until now to definitively rearrange the widget.) +*/ +void SpinBox2::showEvent(QShowEvent*) +{ + arrange(); +} + +QSize SpinBox2::sizeHint() const +{ + getMetrics(); + QSize size = mSpinbox->sizeHint(); + size.setWidth(size.width() - xSpinbox + wUpdown2 + wGap); + return size; +} + +QSize SpinBox2::minimumSizeHint() const +{ + getMetrics(); + QSize size = mSpinbox->minimumSizeHint(); + size.setWidth(size.width() - xSpinbox + wUpdown2 + wGap); + return size; +} + +void SpinBox2::styleChange(QStyle&) +{ + if (mirrorStyle(style())) + mSpinMirror->show(); // show rounded corners with Plastik etc. + else + mSpinMirror->hide(); // keep normal shading with other styles + arrange(); +} + +/****************************************************************************** +* Called when the extra pair of spin buttons has repainted after a style change. +* Updates the mirror image of the spin buttons. +*/ +void SpinBox2::updateMirror() +{ + mSpinMirror->setNormalButtons(QPixmap::grabWidget(mUpdown2Frame, 0, 0)); +} + +/****************************************************************************** +* Set the positions and sizes of all the child widgets. +*/ +void SpinBox2::arrange() +{ + getMetrics(); + QRect arrowRect = QStyle::visualRect(QRect(0, 0, wUpdown2, height()), this); + mUpdown2Frame->setGeometry(arrowRect); + mUpdown2->setGeometry(-xUpdown2, 0, mUpdown2->width(), height()); + mSpinboxFrame->setGeometry(QStyle::visualRect(QRect(wUpdown2 + wGap, 0, width() - wUpdown2 - wGap, height()), this)); + mSpinbox->setGeometry(-xSpinbox, 0, mSpinboxFrame->width() + xSpinbox, height()); + mSpinMirror->resize(wUpdown2, mUpdown2->height()); + mSpinMirror->setGeometry(arrowRect); +//mSpinMirror->setGeometry(QStyle::visualRect(QRect(0, 11, wUpdown2, height()), this)); + mSpinMirror->setNormalButtons(QPixmap::grabWidget(mUpdown2Frame, 0, 0)); +} + +/****************************************************************************** +* Calculate the width and position of the extra pair of spin buttons. +* Style-specific adjustments are made for a better appearance. +*/ +void SpinBox2::getMetrics() const +{ + QRect rect = mUpdown2->style().querySubControlMetrics(QStyle::CC_SpinWidget, mUpdown2, QStyle::SC_SpinWidgetButtonField); + if (style().inherits("PlastikStyle")) + rect.setLeft(rect.left() - 1); // Plastik excludes left border from spin widget rectangle + xUpdown2 = mReverseLayout ? 0 : rect.left(); + wUpdown2 = mUpdown2->width() - rect.left(); + xSpinbox = mSpinbox->style().querySubControlMetrics(QStyle::CC_SpinWidget, mSpinbox, QStyle::SC_SpinWidgetEditField).left(); + wGap = 0; + + // Make style-specific adjustments for a better appearance + if (style().inherits("QMotifPlusStyle")) + { + xSpinbox = 0; // show the edit control left border + wGap = 2; // leave a space to the right of the left-hand pair of spin buttons + } +} + +/****************************************************************************** +* Called when the extra pair of spin buttons is clicked to step the value. +* Normally this is a page step, but with a right-to-left language where the +* button functions are reversed, this is a line step. +*/ +void SpinBox2::stepPage(int step) +{ + if (abs(step) == mUpdown2->lineStep()) + mSpinbox->setValue(mUpdown2->value()); + else + { + // It's a shift step + int oldValue = mSpinbox->value(); + if (!reverseButtons()) + { + // The button pairs have the normal function. + // Page shift stepping - step up or down to a multiple of the + // shift page increment, leaving unchanged the part of the value + // which is the remainder from the page increment. + if (oldValue >= 0) + oldValue -= oldValue % mUpdown2->lineStep(); + else + oldValue += (-oldValue) % mUpdown2->lineStep(); + } + int adjust = mSpinbox->shiftStepAdjustment(oldValue, step); + if (adjust == -step + && ((step > 0 && oldValue + step >= mSpinbox->maxValue()) + || (step < 0 && oldValue + step <= mSpinbox->minValue()))) + adjust = 0; // allow stepping to the minimum or maximum value + mSpinbox->addValue(adjust + step); + } + bool focus = mSpinbox->selectOnStep() && mUpdown2->hasFocus(); + if (focus) + mSpinbox->selectAll(); + + // Make the covering arrows image show the pressed arrow + mSpinMirror->redraw(QPixmap::grabWidget(mUpdown2Frame, 0, 0)); +} + + +/*============================================================================= += Class SpinBox2::MainSpinBox +=============================================================================*/ + +/****************************************************************************** +* Return the initial adjustment to the value for a shift step up or down, for +* the main (visible) spin box. +* Normally this is a line step, but with a right-to-left language where the +* button functions are reversed, this is a page step. +*/ +int SpinBox2::MainSpinBox::shiftStepAdjustment(int oldValue, int shiftStep) +{ + if (owner->reverseButtons()) + { + // The button pairs have the opposite function from normal. + // Page shift stepping - step up or down to a multiple of the + // shift page increment, leaving unchanged the part of the value + // which is the remainder from the page increment. + if (oldValue >= 0) + oldValue -= oldValue % lineStep(); + else + oldValue += (-oldValue) % lineStep(); + } + return SpinBox::shiftStepAdjustment(oldValue, shiftStep); +} + + +/*============================================================================= += Class ExtraSpinBox +=============================================================================*/ + +/****************************************************************************** +* Repaint the widget. +* If it's the first time since a style change, tell the parent SpinBox2 to +* update the SpinMirror with the new unpressed button image. We make the +* presumably reasonable assumption that when a style change occurs, the spin +* buttons are unpressed. +*/ +void ExtraSpinBox::paintEvent(QPaintEvent* e) +{ + SpinBox::paintEvent(e); + if (mNewStylePending) + { + mNewStylePending = false; + emit styleUpdated(); + } +} + + +/*============================================================================= += Class SpinMirror +=============================================================================*/ + +SpinMirror::SpinMirror(SpinBox* spinbox, QFrame* spinFrame, QWidget* parent, const char* name) + : QCanvasView(new QCanvas, parent, name), + mSpinbox(spinbox), + mSpinFrame(spinFrame), + mReadOnly(false) +{ + setVScrollBarMode(QScrollView::AlwaysOff); + setHScrollBarMode(QScrollView::AlwaysOff); + setFrameStyle(QFrame::NoFrame); + + // Find the spin widget which is part of the spin box, in order to + // pass on its shift-button presses. + QObjectList* spinwidgets = spinbox->queryList("QSpinWidget", 0, false, true); + mSpinWidget = (SpinBox*)spinwidgets->getFirst(); + delete spinwidgets; +} + +void SpinMirror::setNormalButtons(const QPixmap& px) +{ + mNormalButtons = px; + redraw(mNormalButtons); +} + +void SpinMirror::redraw() +{ + redraw(QPixmap::grabWidget(mSpinFrame, 0, 0)); +} + +void SpinMirror::redraw(const QPixmap& px) +{ + QCanvas* c = canvas(); + c->setBackgroundPixmap(px); + c->setAllChanged(); + c->update(); +} + +void SpinMirror::resize(int w, int h) +{ + canvas()->resize(w, h); + QCanvasView::resize(w, h); + resizeContents(w, h); + setWorldMatrix(QWMatrix(-1, 0, 0, 1, w - 1, 0)); // mirror left to right +} + +/****************************************************************************** +* Pass on all mouse events to the spinbox which we're covering up. +*/ +void SpinMirror::contentsMouseEvent(QMouseEvent* e) +{ + if (mReadOnly) + return; + QPoint pt = contentsToViewport(e->pos()); + pt.setX(pt.x() + mSpinbox->upRect().left()); + QApplication::postEvent(mSpinWidget, new QMouseEvent(e->type(), pt, e->button(), e->state())); + + // If the mouse button has been pressed or released, refresh the spin buttons + switch (e->type()) + { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + QTimer::singleShot(0, this, SLOT(redraw())); + break; + default: + break; + } +} + +/****************************************************************************** +* Pass on all mouse events to the spinbox which we're covering up. +*/ +void SpinMirror::contentsWheelEvent(QWheelEvent* e) +{ + if (mReadOnly) + return; + QPoint pt = contentsToViewport(e->pos()); + pt.setX(pt.x() + mSpinbox->upRect().left()); + QApplication::postEvent(mSpinWidget, new QWheelEvent(pt, e->delta(), e->state(), e->orientation())); +} + +/****************************************************************************** +* Pass on to the main spinbox events which are needed to activate mouseover and +* other graphic effects when the mouse cursor enters and leaves the widget. +*/ +bool SpinMirror::event(QEvent* e) +{ + switch (e->type()) + { + case QEvent::Leave: + case QEvent::Enter: + QApplication::postEvent(mSpinWidget, new QEvent(e->type())); + QTimer::singleShot(0, this, SLOT(redraw())); + break; + case QEvent::FocusIn: + mSpinbox->setFocus(); + QTimer::singleShot(0, this, SLOT(redraw())); + break; + default: + break; + } + return QCanvasView::event(e); +} + + +/*============================================================================= += Local functions +=============================================================================*/ + +/****************************************************************************** +* Determine whether the extra pair of spin buttons needs to be mirrored +* left-to-right in the specified style. +*/ +static bool mirrorStyle(const QStyle& style) +{ + for (const char** s = mirrorStyles; *s; ++s) + if (style.inherits(*s)) + return true; + return false; +} |