diff --git a/klineal.cpp b/klineal.cpp index 8b5d3c3..0f9bc48 100644 --- a/klineal.cpp +++ b/klineal.cpp @@ -1,933 +1,931 @@ /*************************************************************************** klineal.cpp - description ------------------- Begin : Fri Oct 13 2000 Copyright : 2000 by Till Krech 2008 by Mathias Soeken 2017 by Aurélien Gâteau ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "klineal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "krulerconfig.h" #ifdef KRULER_HAVE_X11 #include #include #endif #include "kruler.h" #include "krulersystemtray.h" #include "ui_cfg_appearance.h" #include "ui_cfg_advanced.h" static const int RESIZE_HANDLE_LENGTH = 7; static const int RESIZE_HANDLE_THICKNESS = 24; static const qreal RESIZE_HANDLE_OPACITY = 0.3; static const int SMALL_TICK_SIZE = 6; static const int MEDIUM1_TICK_SIZE = 10; static const int MEDIUM2_TICK_SIZE = 15; static const int LARGE_TICK_SIZE = 18; static const qreal TICK_OPACITY = 0.3; static const int THICKNESS = 70; static const qreal OVERLAY_OPACITY = 0.1; static const qreal OVERLAY_BORDER_OPACITY = 0.3; static const int INDICATOR_MARGIN = 6; static const int INDICATOR_RECT_RADIUS = 3; static const qreal INDICATOR_RECT_OPACITY = 0.6; static const int CURSOR_SIZE = 15; // Must be an odd number /** * create the thingy with no borders and set up * its members */ KLineal::KLineal( QWidget *parent ) : QWidget( parent ) { setAttribute( Qt::WA_TranslucentBackground ); KWindowSystem::setType( winId(), NET::Override ); // or NET::Normal KWindowSystem::setState( winId(), NET::KeepAbove ); setWindowTitle( i18nc( "@title:window", "KRuler" ) ); setMinimumSize( THICKNESS, THICKNESS ); setMaximumSize( 8000, 8000 ); setWhatsThis( i18n( "This is a tool to measure pixel distances on the screen. " "It is useful for working on layouts of dialogs, web pages etc." ) ); setMouseTracking( true ); mColor = RulerSettings::self()->bgColor(); mScaleFont = RulerSettings::self()->scaleFont(); int len = RulerSettings::self()->length(); mHorizontal = RulerSettings::self()->horizontal(); mLeftToRight = RulerSettings::self()->leftToRight(); mOffset = RulerSettings::self()->offset(); mRelativeScale = RulerSettings::self()->relativeScale(); mAlwaysOnTopLayer = RulerSettings::self()->alwaysOnTop(); if ( mHorizontal ) { resize( QSize( len, THICKNESS ) ); } else { resize( QSize( THICKNESS, len ) ); } createCrossCursor(); //BEGIN setup menu and actions mActionCollection = new KActionCollection( this ); mActionCollection->setConfigGroup( QStringLiteral( "Actions" ) ); mMenu = new QMenu( this ); addAction( mMenu, QIcon::fromTheme( QStringLiteral( "object-rotate-left" ) ), i18n( "Rotate" ), this, SLOT(rotate()), Qt::Key_R, QStringLiteral( "turn_right" ) ); QMenu* scaleMenu = new QMenu( i18n( "&Scale" ), this ); mScaleDirectionAction = addAction( scaleMenu, QIcon(), i18n( "Right to Left" ), this, SLOT(switchDirection()), Qt::Key_D, QStringLiteral( "right_to_left" ) ); mCenterOriginAction = addAction( scaleMenu, QIcon(), i18n( "Center Origin" ), this, SLOT(centerOrigin()), Qt::Key_C, QStringLiteral( "center_origin" ) ); mCenterOriginAction->setEnabled( !mRelativeScale ); mOffsetAction = addAction( scaleMenu, QIcon(), i18n( "Offset..." ), this, SLOT(slotOffset()), Qt::Key_O, QStringLiteral( "set_offset" ) ); mOffsetAction->setEnabled( !mRelativeScale ); scaleMenu->addSeparator(); QAction *relativeScaleAction = addAction( scaleMenu, QIcon(), i18n( "Percentage" ), nullptr, nullptr, QKeySequence(), QStringLiteral( "toggle_percentage" ) ); relativeScaleAction->setCheckable( true ); relativeScaleAction->setChecked( mRelativeScale ); connect(relativeScaleAction, &QAction::toggled, this, &KLineal::switchRelativeScale); mMenu->addMenu( scaleMenu ); mOpacity = RulerSettings::self()->opacity(); QMenu* opacityMenu = new QMenu( i18n( "O&pacity" ), this ); QWidgetAction *opacityAction = new QWidgetAction( this ); QSlider *slider = new QSlider( this ); slider->setMinimum( 30 ); slider->setMaximum( 255 ); slider->setSingleStep( 1 ); slider->setOrientation( Qt::Horizontal ); slider->setValue( RulerSettings::self()->opacity() ); // Show ticks so that the slider is a bit taller, thus easier to grab slider->setTickPosition( QSlider::TicksBothSides ); slider->setTickInterval( 30 ); connect(slider, &QSlider::valueChanged, this, &KLineal::slotOpacity); opacityAction->setDefaultWidget( slider ); opacityMenu->addAction( opacityAction ); mMenu->addMenu( opacityMenu ); QAction *keyBindings = mActionCollection->addAction( KStandardAction::KeyBindings, this, SLOT(slotKeyBindings()) ); mMenu->addAction( keyBindings ); QAction *preferences = mActionCollection->addAction( KStandardAction::Preferences, this, SLOT(slotPreferences()) ); mMenu->addAction( preferences ); mMenu->addSeparator(); mMenu->addMenu( ( new KHelpMenu( this, KAboutData::applicationData(), true ) )->menu() ); mMenu->addSeparator(); if ( RulerSettings::self()->trayIcon() ) { createSystemTray(); } QAction *quit = mActionCollection->addAction( KStandardAction::Quit, qApp, SLOT(quit()) ); mMenu->addAction( quit ); mActionCollection->associateWidget( this ); mActionCollection->readSettings(); mLastClickPos = geometry().topLeft() + QPoint( width() / 2, height() / 2 ); setWindowFlags( mAlwaysOnTopLayer ? Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint : Qt::FramelessWindowHint ); setHorizontal( mHorizontal ); } KLineal::~KLineal() { delete mTrayIcon; } void KLineal::createCrossCursor() { QPixmap pix( CURSOR_SIZE, CURSOR_SIZE ); int halfSize = CURSOR_SIZE / 2; { pix.fill( Qt::transparent ); QPainter painter( &pix ); painter.setPen( Qt::red ); painter.drawLine( 0, halfSize, CURSOR_SIZE - 1, halfSize ); painter.drawLine( halfSize, 0, halfSize, CURSOR_SIZE - 1 ); } mCrossCursor = QCursor( pix, halfSize, halfSize ); } void KLineal::createSystemTray() { mCloseAction = mActionCollection->addAction( KStandardAction::Close, this, SLOT(slotClose()) ); mMenu->addAction( mCloseAction ); if ( !mTrayIcon ) { mTrayIcon = new KRulerSystemTray( QStringLiteral( "kruler" ), this, mActionCollection ); mTrayIcon->setCategory( KStatusNotifierItem::ApplicationStatus ); } } QAction* KLineal::addAction( QMenu *menu, const QIcon& icon, const QString& text, const QObject* receiver, const char* member, const QKeySequence &shortcut, const QString& name ) { QAction *action = new QAction( icon, text, mActionCollection ); mActionCollection->setDefaultShortcut( action, shortcut ); if ( receiver ) { connect( action, SIGNAL(triggered()), receiver, member ); } menu->addAction( action ); mActionCollection->addAction( name, action ); return action; } void KLineal::slotClose() { hide(); } void KLineal::slotQuit() { qApp->quit(); } void KLineal::move( int x, int y ) { move( QPoint( x, y ) ); } void KLineal::move(const QPoint &p) { setGeometry( QRect( p, size() ) ); } QPoint KLineal::pos() const { return frameGeometry().topLeft(); } int KLineal::x() const { return pos().x(); } int KLineal::y() const { return pos().y(); } void KLineal::drawBackground( QPainter& painter ) { QColor a, b, bg = mColor; QLinearGradient gradient; if ( mHorizontal ) { a = bg.lighter( 120 ); b = bg.darker( 130 ); gradient = QLinearGradient( 1, 0, 1, height() ); } else { a = bg.lighter( 120 ); b = bg.darker( 130 ); gradient = QLinearGradient( 0, 1, width(), 1 ); } a.setAlpha( mOpacity ); b.setAlpha( mOpacity ); gradient.setColorAt( 0, a ); gradient.setColorAt( 1, b ); painter.fillRect( rect(), QBrush( gradient ) ); } void KLineal::setHorizontal( bool horizontal ) { QRect r = frameGeometry(); if ( mHorizontal != horizontal ) { r.setSize( r.size().transposed() ); } mHorizontal = horizontal; QPoint center = mLastClickPos; if ( mClicked ) { center = mLastClickPos; mClicked = false; } else { center = r.topLeft() + QPoint( width() / 2, height() / 2 ); } QPoint newTopLeft = QPoint( center.x() - height() / 2, center.y() - width() / 2 ); r.moveTo(newTopLeft); QRect desktop = QApplication::desktop()->screenGeometry( this ); if ( r.width() > desktop.width() ) { r.setWidth( desktop.width() ); } if ( r.height() > desktop.height() ) { r.setHeight( desktop.height() ); } if ( r.top() < desktop.top() ) { r.moveTop( desktop.top() ); } if ( r.bottom() > desktop.bottom() ) { r.moveBottom( desktop.bottom() ); } if ( r.left() < desktop.left() ) { r.moveLeft( desktop.left() ); } if ( r.right() > desktop.right() ) { r.moveRight( desktop.right() ); } setGeometry( r ); updateScaleDirectionMenuItem(); saveSettings(); } void KLineal::rotate() { setHorizontal( !mHorizontal ); } void KLineal::updateScaleDirectionMenuItem() { if ( !mScaleDirectionAction ) return; QString label; if ( mHorizontal ) { label = mLeftToRight ? i18n( "Right to Left" ) : i18n( "Left to Right" ); } else { label = mLeftToRight ? i18n( "Bottom to Top" ) : i18n( "Top to Bottom" ); } mScaleDirectionAction->setText( label ); } QRect KLineal::beginRect() const { int shortLen = RESIZE_HANDLE_THICKNESS; return mHorizontal ? QRect( 0, ( height() - shortLen ) / 2 + 1, RESIZE_HANDLE_LENGTH, shortLen ) : QRect( ( width() - shortLen ) / 2, 0, shortLen, RESIZE_HANDLE_LENGTH ); } QRect KLineal::endRect() const { int shortLen = RESIZE_HANDLE_THICKNESS; return mHorizontal ? QRect( width() - RESIZE_HANDLE_LENGTH, ( height() - shortLen ) / 2 + 1, RESIZE_HANDLE_LENGTH, shortLen ) : QRect( ( width() - shortLen ) / 2, height() - RESIZE_HANDLE_LENGTH, shortLen, RESIZE_HANDLE_LENGTH ); } Qt::CursorShape KLineal::resizeCursor() const { return mHorizontal ? Qt::SizeHorCursor : Qt::SizeVerCursor; } void KLineal::switchDirection() { mLeftToRight = !mLeftToRight; updateScaleDirectionMenuItem(); repaint(); saveSettings(); } void KLineal::centerOrigin() { mOffset = -( length() / 2 ); repaint(); saveSettings(); } void KLineal::slotOffset() { bool ok; int newOffset = QInputDialog::getInt( this, i18nc( "@title:window", "Scale Offset" ), i18n( "Offset:" ), mOffset, -2147483647, 2147483647, 1, &ok ); if ( ok ) { mOffset = newOffset; repaint(); saveSettings(); } } void KLineal::slotOpacity( int value ) { mOpacity = value; repaint(); RulerSettings::self()->setOpacity( value ); RulerSettings::self()->save(); } void KLineal::slotKeyBindings() { KShortcutsDialog::configure( mActionCollection ); } void KLineal::slotPreferences() { KConfigDialog *dialog = new KConfigDialog( this, QStringLiteral( "settings" ), RulerSettings::self() ); Ui::ConfigAppearance appearanceConfig; QWidget *appearanceConfigWidget = new QWidget( dialog ); appearanceConfig.setupUi( appearanceConfigWidget ); dialog->addPage( appearanceConfigWidget, i18n( "Appearance" ), QStringLiteral( "preferences-desktop-default-applications" ) ); #ifdef KRULER_HAVE_X11 // Advanced page only contains the "Native moving" and "Always on top" settings, disable when not running on X11 if ( QX11Info::isPlatformX11() ) { Ui::ConfigAdvanced advancedConfig; QWidget *advancedConfigWidget = new QWidget( dialog ); advancedConfig.setupUi( advancedConfigWidget ); dialog->addPage( advancedConfigWidget, i18n( "Advanced" ), QStringLiteral( "preferences-other" ) ); } #endif connect(dialog, &KConfigDialog::settingsChanged, this, &KLineal::loadConfig); dialog->exec(); delete dialog; } void KLineal::loadConfig() { mColor = RulerSettings::self()->bgColor(); mScaleFont = RulerSettings::self()->scaleFont(); mAlwaysOnTopLayer = RulerSettings::self()->alwaysOnTop(); saveSettings(); setWindowFlags( mAlwaysOnTopLayer ? Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint : Qt::FramelessWindowHint ); if ( RulerSettings::self()->trayIcon() ) { if ( !mTrayIcon ) { createSystemTray(); } } else { delete mTrayIcon; mTrayIcon = nullptr; if ( mCloseAction ) { mCloseAction->setVisible( false ); } } show(); repaint(); } void KLineal::switchRelativeScale( bool checked ) { mRelativeScale = checked; mCenterOriginAction->setEnabled( !mRelativeScale ); mOffsetAction->setEnabled( !mRelativeScale ); repaint(); saveSettings(); } /** * save the ruler color to the config file */ void KLineal::saveSettings() { RulerSettings::self()->setBgColor( mColor ); RulerSettings::self()->setScaleFont( mScaleFont ); RulerSettings::self()->setLength( length() ); RulerSettings::self()->setHorizontal( mHorizontal ); RulerSettings::self()->setLeftToRight( mLeftToRight ); RulerSettings::self()->setOffset( mOffset ); RulerSettings::self()->setRelativeScale( mRelativeScale ); RulerSettings::self()->setAlwaysOnTop( mAlwaysOnTopLayer ); RulerSettings::self()->save(); } /** * lets the context menu appear at current cursor position */ void KLineal::showMenu() { QPoint pos = QCursor::pos(); mMenu->popup( pos ); } bool KLineal::isResizing() const { return mouseGrabber() == this && ( mRulerState == StateBegin || mRulerState == StateEnd ); } int KLineal::length() const { return mHorizontal ? width() : height(); } QPoint KLineal::localCursorPos() const { // For some reason mapFromGlobal( QCursor::pos() ) thinks the ruler is at 0, 0 at startup. // compute the position ourselves to avoid that. return QCursor::pos() - pos(); } QString KLineal::indicatorText() const { int xy = mHorizontal ? localCursorPos().x() : localCursorPos().y(); if ( !mRelativeScale ) { int len = mLeftToRight ? xy + 1 : length() - xy; return i18n( "%1 px", len ); } else { int len = ( xy * 100.f ) / length(); if ( !mLeftToRight ) { len = 100 - len; } return i18n( "%1%", len ); } } void KLineal::keyPressEvent( QKeyEvent *e ) { QPoint dist; switch ( e->key() ) { case Qt::Key_F1: KHelpClient::invokeHelp(); return; case Qt::Key_Left: dist.setX( -1 ); break; case Qt::Key_Right: dist.setX( 1 ); break; case Qt::Key_Up: dist.setY( -1 ); break; case Qt::Key_Down: dist.setY( 1 ); break; default: QWidget::keyPressEvent(e); return; } if ( e->modifiers() & Qt::ShiftModifier ) { dist *= 10; } if ( e->modifiers() & Qt::AltModifier ) { QCursor::setPos( QCursor::pos() + dist ); } else { move( pos() + dist ); update(); } KNotification::event( QString(), QStringLiteral( "cursormove" ), QString() ); } void KLineal::leaveEvent( QEvent *e ) { Q_UNUSED( e ); update(); } void KLineal::mouseMoveEvent( QMouseEvent *inEvent ) { Q_UNUSED( inEvent ); if ( mRulerState >= StateMove ) { if ( mouseGrabber() != this ) { return; } if ( mRulerState == StateMove ) { move( QCursor::pos() - mDragOffset ); } else if ( mRulerState == StateBegin ) { QRect r = geometry(); if ( mHorizontal ) { r.setLeft( QCursor::pos().x() - mDragOffset.x() ); } else { r.setTop( QCursor::pos().y() - mDragOffset.y() ); } setGeometry( r ); } else if ( mRulerState == StateEnd ) { QPoint end = QCursor::pos() + mDragOffset - pos(); QSize size = mHorizontal ? QSize( end.x(), height() ) : QSize( width(), end.y() ); resize( size ); } } else { QPoint cpos = localCursorPos(); mRulerState = StateNone; if ( beginRect().contains( cpos ) || endRect().contains( cpos) ) { setCursor( resizeCursor() ); } else { setCursor( mCrossCursor ); } update(); } } /** * overwritten for dragging and context menu */ void KLineal::mousePressEvent( QMouseEvent *inEvent ) { mLastClickPos = QCursor::pos(); QRect gr = geometry(); mDragOffset = mLastClickPos - gr.topLeft(); if ( inEvent->button() == Qt::LeftButton ) { if ( mRulerState < StateMove ) { if ( beginRect().contains( mDragOffset ) ) { mRulerState = StateBegin; grabMouse( resizeCursor() ); } else if ( endRect().contains( mDragOffset ) ) { mDragOffset = gr.bottomRight() - mLastClickPos; mRulerState = StateEnd; grabMouse( resizeCursor() ); } else { if ( nativeMove() ) { startNativeMove( inEvent ); } else { mRulerState = StateMove; grabMouse( Qt::SizeAllCursor ); } } } } else if ( inEvent->button() == Qt::MidButton ) { mClicked = true; rotate(); } else if ( inEvent->button() == Qt::RightButton ) { showMenu(); } } #ifdef KRULER_HAVE_X11 bool KLineal::nativeMove() const { return QX11Info::isPlatformX11() && RulerSettings::self()->nativeMoving(); } void KLineal::startNativeMove( QMouseEvent *inEvent ) { xcb_ungrab_pointer( QX11Info::connection(), QX11Info::appTime() ); NETRootInfo wm_root( QX11Info::connection(), NET::WMMoveResize ); wm_root.moveResizeRequest( winId(), inEvent->globalX(), inEvent->globalY(), NET::Move ); } void KLineal::stopNativeMove( QMouseEvent *inEvent ) { NETRootInfo wm_root( QX11Info::connection(), NET::WMMoveResize ); wm_root.moveResizeRequest( winId(), inEvent->globalX(), inEvent->globalY(), NET::MoveResizeCancel ); } #else bool KLineal::nativeMove() const { return false; } void KLineal::startNativeMove( QMouseEvent *inEvent ) { Q_UNUSED( inEvent ); } void KLineal::stopNativeMove( QMouseEvent *inEvent ) { Q_UNUSED( inEvent ); } #endif /** * overwritten for dragging */ void KLineal::mouseReleaseEvent( QMouseEvent *inEvent ) { if ( mRulerState != StateNone ) { mRulerState = StateNone; releaseMouse(); saveSettings(); } else if ( nativeMove() ) { stopNativeMove( inEvent ); } } void KLineal::wheelEvent( QWheelEvent *e ) { - int numDegrees = e->delta() / 8; + int numDegrees = e->angleDelta().y() / 8; int numSteps = numDegrees / 15; // changing offset if ( e->buttons() == Qt::LeftButton ) { if ( !mRelativeScale ) { mOffset += numSteps; repaint(); saveSettings(); } } QWidget::wheelEvent( e ); } /** * draws the scale according to the orientation */ void KLineal::drawScale( QPainter &painter ) { painter.setPen( Qt::black ); QFont font = mScaleFont; painter.setFont( font ); int longLen = length(); if ( !mRelativeScale ) { int digit; int len; // Draw from -1 to longLen rather than from 0 to longLen - 1 to take into // account the offset applied in drawScaleTick for ( int x = -1; x <= longLen; ++x ) { if ( mLeftToRight ) { digit = x + mOffset; } else { digit = longLen - x + mOffset; } if ( digit % 2 ) continue; if ( digit % 100 == 0 ) { len = LARGE_TICK_SIZE; } else if ( digit % 20 == 0 ) { len = MEDIUM2_TICK_SIZE; } else if (digit % 10 == 0) { len = MEDIUM1_TICK_SIZE; } else { len = SMALL_TICK_SIZE; } if ( digit % 100 == 0 && digit != 0 ) { - QString units; - units.sprintf( "%d", digit ); + QString units = QStringLiteral("%1").arg(digit); drawScaleText( painter, x, units ); } drawScaleTick( painter, x, len ); } } else { float step = longLen / 100.f; int len; for ( int i = 0; i <= 100; ++i ) { int x = (int)( i * step ); if ( i % 10 == 0 && i != 0 && i != 100 ) { - QString units; int value = mLeftToRight ? i : ( 100 - i ); - units.sprintf( "%d%%", value ); + const QString units = QString::asprintf( "%d%%", value ); drawScaleText( painter, x, units ); len = MEDIUM2_TICK_SIZE; } else { len = SMALL_TICK_SIZE; } drawScaleTick( painter, x, len ); } } } void KLineal::drawScaleText( QPainter &painter, int x, const QString &text ) { QFontMetrics metrics = painter.fontMetrics(); QSize textSize = metrics.size( Qt::TextSingleLine, text ); int w = width(); int h = height(); int tw = textSize.width(); int th = metrics.ascent(); if ( mHorizontal ) { painter.drawText( x - tw / 2, (h + th) / 2, text ); } else { painter.drawText( (w - tw) / 2, x + th / 2, text ); } } void KLineal::drawScaleTick( QPainter &painter, int x, int len ) { painter.setOpacity( TICK_OPACITY ); int w = width(); int h = height(); // Offset by one because we are measuring lengths, not positions, so when the // indicator is at position 0 it measures a length of 1 pixel. if ( mLeftToRight ) { --x; } else { ++x; } if ( mHorizontal ) { painter.drawLine( x, 0, x, len ); painter.drawLine( x, h, x, h - len ); } else { painter.drawLine( 0, x, len, x ); painter.drawLine( w, x, w - len, x ); } painter.setOpacity( 1 ); } void KLineal::drawResizeHandle( QPainter &painter, Qt::Edge edge ) { QRect rect; switch ( edge ) { case Qt::LeftEdge: case Qt::TopEdge: rect = beginRect(); break; case Qt::RightEdge: case Qt::BottomEdge: rect = endRect(); break; } painter.setOpacity( RESIZE_HANDLE_OPACITY ); if ( mHorizontal ) { int y1 = ( THICKNESS - RESIZE_HANDLE_THICKNESS ) / 2; int y2 = y1 + RESIZE_HANDLE_THICKNESS - 1; for ( int x = rect.left() + 1; x < rect.right(); x += 2 ) { painter.drawLine( x, y1, x, y2 ); } } else { int x1 = ( THICKNESS - RESIZE_HANDLE_THICKNESS ) / 2; int x2 = x1 + RESIZE_HANDLE_THICKNESS - 1; for ( int y = rect.top() + 1; y < rect.bottom(); y += 2 ) { painter.drawLine( x1, y, x2, y ); } } painter.setOpacity( 1 ); } void KLineal::drawIndicatorOverlay( QPainter &painter, int xy ) { painter.setPen( Qt::red ); painter.setOpacity( OVERLAY_OPACITY ); if ( mHorizontal ) { QPointF p1( mLeftToRight ? 0 : width(), 0 ); QPointF p2( xy, THICKNESS ); QRectF rect( p1, p2 ); painter.fillRect( rect, Qt::red ); painter.setOpacity( OVERLAY_BORDER_OPACITY ); painter.drawLine( xy, 0, xy, THICKNESS ); } else { QPointF p1( 0, mLeftToRight ? 0 : height() ); QPointF p2( THICKNESS, xy ); QRectF rect( p1, p2 ); painter.fillRect( rect, Qt::red ); painter.setOpacity( OVERLAY_BORDER_OPACITY ); painter.drawLine( 0, xy, THICKNESS, xy ); } } void KLineal::drawIndicatorText( QPainter &painter, int xy ) { QString text = indicatorText(); painter.setFont( font() ); QFontMetrics fm = QFontMetrics( font() ); int tx, ty; int tw = fm.boundingRect(text).width(); if ( mHorizontal ) { tx = xy + INDICATOR_MARGIN; if ( tx + tw > width() ) { tx = xy - tw - INDICATOR_MARGIN; } ty = height() - SMALL_TICK_SIZE - INDICATOR_RECT_RADIUS; } else { tx = ( width() - tw ) / 2; ty = xy + fm.ascent() + INDICATOR_MARGIN; if ( ty > height() ) { ty = xy - INDICATOR_MARGIN; } } // Draw background rect painter.setRenderHint( QPainter::Antialiasing ); painter.setOpacity( INDICATOR_RECT_OPACITY ); painter.setBrush( Qt::red ); QRectF bgRect( tx, ty - fm.ascent() + 1, tw, fm.ascent() ); bgRect.adjust( -INDICATOR_RECT_RADIUS, -INDICATOR_RECT_RADIUS, INDICATOR_RECT_RADIUS, INDICATOR_RECT_RADIUS ); bgRect.translate( 0.5, 0.5 ); painter.drawRoundedRect( bgRect, INDICATOR_RECT_RADIUS, INDICATOR_RECT_RADIUS ); // Draw text painter.setOpacity( 1 ); painter.setPen( Qt::white ); painter.drawText( tx, ty, text ); } /** * actually draws the ruler */ void KLineal::paintEvent(QPaintEvent *inEvent ) { Q_UNUSED( inEvent ); QPainter painter( this ); drawBackground( painter ); drawScale( painter ); drawResizeHandle( painter, mHorizontal ? Qt::LeftEdge : Qt::TopEdge ); drawResizeHandle( painter, mHorizontal ? Qt::RightEdge : Qt::BottomEdge ); if ( underMouse() && !isResizing() ) { int xy = mHorizontal ? localCursorPos().x() : localCursorPos().y(); drawIndicatorOverlay( painter, xy ); drawIndicatorText( painter, xy ); } }