diff --git a/CMakeLists.txt b/CMakeLists.txt index 1df3fe0..e8953bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,72 +1,72 @@ project(kruler) cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) set(QT_MIN_VERSION "5.2.0") find_package(ECM 1.7.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) add_definitions(-DTRANSLATION_DOMAIN="kruler") include(KDEInstallDirs) include(KDECompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(ECMInstallIcons) include(FeatureSummary) include(ECMAddAppIcon) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Widgets ) find_package(KF5 REQUIRED COMPONENTS DocTools I18n Notifications WindowSystem XmlGui ) if (NOT APPLE) find_package(X11) set (KRULER_HAVE_X11 ${X11_FOUND}) if (X11_FOUND) find_package(XCB COMPONENTS XCB) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED X11Extras) endif() endif() configure_file(krulerconfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/krulerconfig.h) add_subdirectory( pics ) add_subdirectory( doc ) ########### next target ############### -set(kruler_SRCS qautosizelabel.cpp klineal.cpp main.cpp krulersystemtray.cpp) +set(kruler_SRCS klineal.cpp main.cpp krulersystemtray.cpp) ki18n_wrap_ui(kruler_SRCS cfg_appearance.ui cfg_advanced.ui) kconfig_add_kcfg_files(kruler_SRCS kruler.kcfgc) file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/pics/*-apps-kruler.png") ecm_add_app_icon(kruler_SRCS ICONS ${ICONS_SRCS}) add_executable(kruler ${kruler_SRCS}) target_link_libraries(kruler KF5::I18n KF5::Notifications KF5::WindowSystem KF5::XmlGui) if (X11_FOUND) target_link_libraries(kruler Qt5::X11Extras ${XCB_LIBRARIES}) endif() install(TARGETS kruler ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install( PROGRAMS org.kde.kruler.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) install( FILES org.kde.kruler.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} ) install( FILES kruler.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFY5RCDIR} ) install( FILES move.wav DESTINATION ${KDE_INSTALL_DATADIR}/kruler/sounds ) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/cfg_appearance.ui b/cfg_appearance.ui index 9c13e27..be80ac5 100644 --- a/cfg_appearance.ui +++ b/cfg_appearance.ui @@ -1,94 +1,80 @@ Mathias Soeken ConfigAppearance 0 0 400 300 0 Background color: Font: Show tray icon - - - - Show rotation buttons - - - - - - - Show close button - - - KColorButton QPushButton
kcolorbutton.h
KFontRequester QWidget
kfontrequester.h
kcfg_BgColor kcfg_TrayIcon toggled(bool) kcfg_CloseButtonVisible setEnabled(bool) 172 100 183 127
diff --git a/doc/index.docbook b/doc/index.docbook index 5de9947..e56417c 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -1,440 +1,244 @@ ]> The &kruler; Handbook Lauri Watts
&Lauri.Watts.mail;
&FDLNotice; 2001 &Lauri.Watts; 2015-05-15 Applications 15.04 &kruler; can be used to measure objects on the screen. KDE KRuler kdegraphics
Introduction &kruler; is a very simple application, with only one aim in life. To -measure pixel distances and colors on your screen. It is useful for working on -layout of dialogs, web pages &etc; +measure pixel distances on your screen. It is useful for working on layout +of dialogs, web pages &etc; To start &kruler;, choose ApplicationsGraphics More Applications Screen Ruler from your application menu. &kruler; &kruler; Clicking with the &LMB; on the &kruler; will turn the cursor to a cross with four arrows and enables you to drag &kruler; around the screen. -When you move the mouse over &kruler;, your cursor will turn into an -elongated arrow, with a circle at one end. As you move the cursor, &kruler; will -display how far from the point marked 0 the circle on the -end of the cursor currently is. &kruler; will also display the -&HTML; color code of the color currently under the circle. -This is very useful for picking out colors from an image. If you move the -mouse far enough that the arrow cursor is no longer touching &kruler;, the -cursor will revert to normal, allowing you to carry on working with your other -applications. +When you move the mouse over &kruler;, your cursor will turn into a +red arrow. As you move the cursor, &kruler; will +display how far from the origin the cursor currently is. + + +You can resize the ruler by moving the mouse over the handle on the +left or right edges of &kruler; (the top or bottom edges when it is oriented +vertically), holding down the &LMB; and dragging the handle. -You can change the orientation in three different ways: +You can change the orientation in two different ways: Clicking the &MMB; switches the ruler from vertical to horizontal orientation -By clicking the rotation buttons to turn 90 degrees to the left or right. -If the rotation buttons are not displayed on the ruler, enable them with Show -rotation buttons in the settings dialog Using the context menu, described in the next chapter Menu Reference Clicking with the &RMB; on the ruler will pop up a context menu, with the following entries: -Orientation - - - -This submenu contains entries that allow you to change the orientation of -&kruler; - - - - - - -N - -Orientation -North - - - -Turns &kruler; so the ruler is horizontal, and the measurements are on the -top (North) of the ruler - - - - - - -E - -Orientation -East - - - -Turns &kruler; so the ruler is vertical, and the measurements are on the -right (East) of the ruler - - - - - - -S - -Orientation -South - - - -Turns &kruler; so the ruler is horizontal, and the measurements are on the -bottom (South) of the ruler - - - - - - -W - -Orientation -West - - - -Turns &kruler; so the ruler is vertical, and the measurements are on the -left (West) of the ruler - - - - - - -R - -Orientation -Turn Right - - - -Turns the ruler 90 Degrees to the right. For example, if it is oriented -South, it will rotate to be oriented West. - - - - - - -L - -Orientation -Turn Left +Rotate -Turns the ruler 90 Degrees to the left. For example, if it is oriented -West, it will rotate to be oriented South. - - - - - - - - -Length - - - -This submenu contains entries that allow you to change the length of -&kruler; - - - - -&Ctrl; -S - -Length -Short - - - -Makes &kruler; short - about 385 pixels long. - - - - - - -&Ctrl;M - -Length -Medium - - - -Makes &kruler; a medium length - about 640 pixels long. - - - - - - -&Ctrl;T - -Length -Tall - - - -Makes &kruler; long - about 960 pixels in length. - - - - - - -&Ctrl;F - -Length -Full Screen Width - - - -Makes &kruler; the same size as your screen width. - - - - - -Length -Length... - - - -Opens a dialog to enter the size in pixel. - - - -Additionally, you can change the length and move the right side of the ruler using the mousewheel. -When holding the &Shift; key the opposite side will change. - - +Switchs &kruler; from vertical to horizontal orientation. Scale This option lets you set the ruler scale to Right to Left (D), Center Origin (C), Offset (O) and Percentage. Changing the offset via the mousewheel is also possible when holding the &LMB;. Opacity This menu item displays a slider to change the opacity of &kruler;. Configure Shortcuts... The Configure Shortcut dialog allows you to assign shortcuts to &kruler; actions, and configure the shortcuts already assigned. For more information, read the section about the Shortcuts of the &kde; Fundamentals. Configure &kruler;... &kruler;'s settings dialog &kruler;'s settings dialog -In this dialog you can change the background color and font, enable rotation and close -buttons on the ruler and enable the tray icon. - - - - - - - -&Ctrl;C - -Copy Color - - - -Copies the &HTML; color code of the color currently under the circle to the clipboard. +In this dialog you can change the background color and font and enable +the tray icon. &Ctrl;W Close Hides &kruler;. It can be shown again using the icon in the system tray. The context menu displays this item only when Show tray icon is checked in the settings dialog. &Ctrl;Q Quit Quits &kruler; &kruler; has the common &kde; Help menu item, for more information read the section about the Help Menu of the &kde; Fundamentals. Credits and License &kruler; Copyright 2000, 2001 Till Krech till@snafu.de Copyright 2009 Mathias Soeken msoeken@tzi.de Thanks to Gunnstein Lye gl@ez.no for the initial port to &kde; 2 Documentation Copyright &Lauri.Watts; &Lauri.Watts.mail; &underFDL; &underGPL; &documentation.index;
diff --git a/doc/kruler.png b/doc/kruler.png index 78712b3..d231218 100644 Binary files a/doc/kruler.png and b/doc/kruler.png differ diff --git a/klineal.cpp b/klineal.cpp index 1a3ba8b..70050e5 100644 --- a/klineal.cpp +++ b/klineal.cpp @@ -1,1225 +1,939 @@ /*************************************************************************** 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 #include #include #include #include #include "krulerconfig.h" #ifdef KRULER_HAVE_X11 #include #include #endif #include "kruler.h" #include "krulersystemtray.h" -#include "qautosizelabel.h" #include "ui_cfg_appearance.h" #include "ui_cfg_advanced.h" -/** - * this is our cursor bitmap: - * a line 48 pixels long with an arrow pointing down - * and a sqare with a one pixel hole at the top (end) - */ -static const uchar cursorBits[] = { - 0x38, 0x28, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, -}; +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 ), - mDragging( false ), - mShortEdgeLen( 70 ), + mRulerState( StateNone ), mCloseAction( 0 ), - mLenMenu( 0 ), // INFO This member could be eventually deleted - // since if mFullScreenAction is initialized - // mLenMenu should have been, too. - mFullScreenAction( 0 ), mScaleDirectionAction( 0 ), mCenterOriginAction( 0 ), mOffsetAction( 0 ), mClicked( false ), mActionCollection( 0 ), - mCloseButton( 0 ), mTrayIcon( 0 ) { setAttribute( Qt::WA_TranslucentBackground ); KWindowSystem::setType( winId(), NET::Override ); // or NET::Normal KWindowSystem::setState( winId(), NET::KeepAbove ); setWindowTitle( i18nc( "@title:window", "KRuler" ) ); - setMinimumSize( 60, 60 ); + setMinimumSize( THICKNESS, THICKNESS ); setMaximumSize( 8000, 8000 ); - setWhatsThis( i18n( "This is a tool to measure pixel distances and colors on the screen. " + 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 ); - QBitmap bim = QBitmap::fromData( QSize( 8, 48 ), cursorBits, QImage::Format_Mono ); - QMatrix m; - m.rotate( 90.0 ); - mNorthCursor = QCursor( bim, bim, 3, 47 ); - bim = bim.transformed( m ); - mEastCursor = QCursor( bim, bim, 0, 3 ); - bim = bim.transformed( m ); - mSouthCursor = QCursor( bim, bim, 4, 0 ); - bim = bim.transformed( m ); - mWestCursor = QCursor( bim, bim, 47, 4 ); - - mCurrentCursor = mNorthCursor; mColor = RulerSettings::self()->bgColor(); mScaleFont = RulerSettings::self()->scaleFont(); - mLongEdgeLen = RulerSettings::self()->length(); - mOrientation = RulerSettings::self()->orientation(); + 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(); - mLabel = new QAutoSizeLabel( this ); - mLabel->setGeometry( 0, height() - 12, 32, 12 ); - mLabel->setWhatsThis( i18n( "This is the current distance measured in pixels." ) ); - mColorLabel = new QAutoSizeLabel( this ); - mColorLabel->setAutoFillBackground( true ); - QFont colorFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); - mColorLabel->setFont( colorFont ); - mColorLabel->move( mLabel->pos() + QPoint(0, 20) ); - mColorLabel->setWhatsThis(i18n("This is the current color in hexadecimal rgb representation" - " as you may use it in HTML or as a QColor name. " - "The rectangles background shows the color of the pixel inside the " - "little square at the end of the line cursor." ) ); - - mBtnRotateLeft = new QToolButton( this ); - mBtnRotateLeft->setIcon( QIcon::fromTheme( QStringLiteral( "object-rotate-left" ) ) ); - mBtnRotateLeft->setToolTip( i18n( "Turn Left" ) ); - connect(mBtnRotateLeft, &QToolButton::clicked, this, &KLineal::turnLeft); - - mBtnRotateRight = new QToolButton( this ); - mBtnRotateRight->setIcon( QIcon::fromTheme( QStringLiteral( "object-rotate-right" ) ) ); - mBtnRotateRight->setToolTip( i18n( "Turn Right" ) ); - connect(mBtnRotateRight, &QToolButton::clicked, this, &KLineal::turnRight); - - resize( QSize( mLongEdgeLen, mShortEdgeLen ) ); + 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 ); mMenu->addSection( i18n( "KRuler" ) ); - QMenu *oriMenu = new QMenu( i18n( "&Orientation"), this ); - addAction( oriMenu, QIcon::fromTheme( QStringLiteral( "kruler-north" ) ), i18nc( "Turn Kruler North", "&North" ), - this, SLOT(setNorth()), Qt::Key_N, QStringLiteral( "turn_north" ) ); - addAction( oriMenu, QIcon::fromTheme( QStringLiteral( "kruler-east" ) ), i18nc( "Turn Kruler East", "&East" ), - this, SLOT(setEast()), Qt::Key_E, QStringLiteral( "turn_east" ) ); - addAction( oriMenu, QIcon::fromTheme( QStringLiteral( "kruler-south" ) ), i18nc( "Turn Kruler South", "&South" ), - this, SLOT(setSouth()), Qt::Key_S, QStringLiteral( "turn_south" ) ); - addAction( oriMenu, QIcon::fromTheme( QStringLiteral( "kruler-west" ) ), i18nc( "Turn Kruler West", "&West" ), - this, SLOT(setWest()), Qt::Key_W, QStringLiteral( "turn_west" ) ); - addAction( oriMenu, QIcon::fromTheme( QStringLiteral( "object-rotate-right" ) ), i18n( "&Turn Right" ), - this, SLOT(turnRight()), Qt::Key_R, QStringLiteral( "turn_right" ) ); - addAction( oriMenu, QIcon::fromTheme( QStringLiteral( "object-rotate-left" ) ), i18n( "Turn &Left" ), - this, SLOT(turnLeft()), Qt::Key_L, QStringLiteral( "turn_left" ) ); - mMenu->addMenu( oriMenu ); - - mLenMenu = new QMenu( i18n( "&Length" ), this ); - addAction( mLenMenu, QIcon(), i18nc( "Make Kruler Height Short", "&Short" ), - this, SLOT(setShortLength()), Qt::CTRL + Qt::Key_S, QStringLiteral( "length_short" ) ); - addAction( mLenMenu, QIcon(), i18nc( "Make Kruler Height Medium", "&Medium" ), - this, SLOT(setMediumLength()), Qt::CTRL + Qt::Key_M, QStringLiteral( "length_medium" ) ); - addAction( mLenMenu, QIcon(), i18nc( "Make Kruler Height Tall", "&Tall" ), - this, SLOT(setTallLength()), Qt::CTRL + Qt::Key_T, QStringLiteral( "length_tall" ) ); - addAction( mLenMenu, QIcon(), i18n("&Full Screen Width"), - this, SLOT(setFullLength()), Qt::CTRL + Qt::Key_F, QStringLiteral( "length_full_length" ) ); - mLenMenu->addSeparator(); - addAction( mLenMenu, QIcon(), i18n( "Length..." ), - this, SLOT(slotLength()), QKeySequence(), QStringLiteral( "set_length" ) ); - mMenu->addMenu( mLenMenu ); + 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" ), 0, 0, 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( 0 ); slider->setMaximum( 255 ); slider->setSingleStep( 1 ); slider->setOrientation( Qt::Horizontal ); slider->setValue( RulerSettings::self()->opacity() ); 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(); - QAction *copyColorAction = mActionCollection->addAction( KStandardAction::Copy, this, SLOT(copyColor()) ); - copyColorAction->setText( i18n( "Copy Color" ) ); - mMenu->addAction( copyColorAction ); - 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 ); - hideLabel(); - setOrientation( mOrientation ); - + setHorizontal( mHorizontal ); } KLineal::~KLineal() { delete mTrayIcon; } -void KLineal::createSystemTray() +void KLineal::createCrossCursor() { - if ( !mCloseAction ) { - mCloseAction = mActionCollection->addAction( KStandardAction::Close, this, SLOT(slotClose()) ); - mMenu->addAction( mCloseAction ); - - mCloseButton = new QToolButton( this ); - mCloseButton->setIcon( mCloseAction->icon() ); - mCloseButton->setToolTip( mCloseAction->text().remove( QLatin1Char( '&' ) ) ); - connect(mCloseButton, &QToolButton::clicked, this, &KLineal::slotClose); - } else { - mCloseAction->setVisible( true ); + 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; - switch ( mOrientation ) { - case North: + if ( mHorizontal ) { a = bg.light( 120 ); b = bg.dark( 130 ); gradient = QLinearGradient( 1, 0, 1, height() ); - break; - - case South: - b = bg.light( 120 ); - a = bg.dark( 130 ); - gradient = QLinearGradient( 1, 0, 1, height() ); - break; - - case West: + } else { a = bg.light( 120 ); b = bg.dark( 130 ); gradient = QLinearGradient( 0, 1, width(), 1 ); - break; - - case East: - b = bg.light( 120 ); - a = bg.dark( 130 ); - gradient = QLinearGradient( 0, 1, width(), 1 ); - break; } a.setAlpha( mOpacity ); b.setAlpha( mOpacity ); gradient.setColorAt( 0, a ); gradient.setColorAt( 1, b ); painter.fillRect( rect(), QBrush( gradient ) ); } -void KLineal::setOrientation( int inOrientation ) +void KLineal::setHorizontal( bool horizontal ) { QRect r = frameGeometry(); - int nineties = (int)inOrientation - (int)mOrientation; - mOrientation = ( inOrientation + 4 ) % 4; - QPoint center = mLastClickPos, newTopLeft; + 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 ); } - if ( nineties % 2 ) { - newTopLeft = QPoint( center.x() - height() / 2, center.y() - width() / 2 ); - } else { - newTopLeft = r.topLeft(); - } - - if ( mOrientation == North || mOrientation == South ) { - r.setSize( QSize( mLongEdgeLen, mShortEdgeLen ) ); - } else { - r.setSize( QSize( mShortEdgeLen, mLongEdgeLen ) ); - } - + 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 ); - switch( mOrientation ) { - case North: - mLabel->move( 4, height()-mLabel->height() - 4 ); - mColorLabel->move( mLabel->pos() + QPoint( 0, -20 ) ); - mCurrentCursor = mNorthCursor; - break; - - case South: - mLabel->move( 4, 4 ); - mColorLabel->move( mLabel->pos() + QPoint( 0, 20 ) ); - mCurrentCursor = mSouthCursor; - break; - - case East: - mLabel->move( 4, 4 ); - mColorLabel->move( mLabel->pos() + QPoint( 0, 20 ) ); - mCurrentCursor = mEastCursor; - break; - - case West: - mLabel->move( width()-mLabel->width() - 4, 4 ); - mColorLabel->move( mLabel->pos() + QPoint( -5, 20 ) ); - mCurrentCursor = mWestCursor; - break; - } - - adjustButtons(); - - if ( mLenMenu && mFullScreenAction ) { - mFullScreenAction->setText( mOrientation % 2 ? i18n( "&Full Screen Height" ) : i18n( "&Full Screen Width" ) ); - } updateScaleDirectionMenuItem(); - setCursor( mCurrentCursor ); - repaint(); saveSettings(); } -void KLineal::setNorth() -{ - setOrientation( North ); -} - -void KLineal::setEast() +void KLineal::rotate() { - setOrientation( East ); -} - -void KLineal::setSouth() -{ - setOrientation( South ); -} - -void KLineal::setWest() -{ - setOrientation( West ); -} - -void KLineal::turnRight() -{ - setOrientation( mOrientation - 1 ); -} - -void KLineal::turnLeft() -{ - setOrientation( mOrientation + 1 ); -} - -void KLineal::reLength( int percentOfScreen ) -{ - if ( percentOfScreen < 10 ) { - return; - } - - QRect r = QApplication::desktop()->screenGeometry( this ); - - if ( mOrientation == North || mOrientation == South ) { - mLongEdgeLen = r.width() * percentOfScreen / 100; - resize( mLongEdgeLen, height() ); - } else { - mLongEdgeLen = r.height() * percentOfScreen / 100; - resize( width(), mLongEdgeLen ); - } - - if ( x() + width() < 10 ) { - move( 10, y() ); - } - - if ( y() + height() < 10 ) { - move( x(), 10 ); - } - - adjustButtons(); - saveSettings(); -} - -void KLineal::reLengthAbsolute( int length ) -{ - if ( length < 100 ) { - return; - } - - mLongEdgeLen = length; - if ( mOrientation == North || mOrientation == South ) { - resize( mLongEdgeLen, height() ); - } else { - resize( width(), mLongEdgeLen ); - } - - if ( x() + width() < 10 ) { - move( 10, y() ); - } - - if ( y() + height() < 10 ) { - move( x(), 10 ); - } - - adjustButtons(); - saveSettings(); + setHorizontal( !mHorizontal ); } void KLineal::updateScaleDirectionMenuItem() { if ( !mScaleDirectionAction ) return; QString label; - if ( mOrientation == North || mOrientation == South ) { + 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 ); } -void KLineal::setShortLength() +QRect KLineal::beginRect() const { - reLength( 30 ); + 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 ); } -void KLineal::setMediumLength() +QRect KLineal::endRect() const { - reLength( 50 ); + 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 ); } -void KLineal::setTallLength() +Qt::CursorShape KLineal::resizeCursor() const { - reLength( 75 ); -} - -void KLineal::setFullLength() -{ - reLength( 100 ); + return mHorizontal ? Qt::SizeHorCursor : Qt::SizeVerCursor; } void KLineal::switchDirection() { mLeftToRight = !mLeftToRight; updateScaleDirectionMenuItem(); repaint(); - adjustLabel(); saveSettings(); } void KLineal::centerOrigin() { - mOffset = -( mLongEdgeLen / 2 ); + mOffset = -( length() / 2 ); repaint(); - adjustLabel(); 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(); - adjustLabel(); saveSettings(); } } -void KLineal::slotLength() -{ - bool ok; - QRect r = QApplication::desktop()->screenGeometry( this ); - int width = ( ( mOrientation == North ) || ( mOrientation == South ) ) ? r.width() : r.height(); - int newLength = QInputDialog::getInt( this, i18nc( "@title:window", "Ruler Length" ), - i18n( "Length:" ), mLongEdgeLen, - 0, width, 1, &ok ); - - if ( ok ) { - reLengthAbsolute( newLength ); - } -} - 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 ); - appearanceConfig.kcfg_CloseButtonVisible->setEnabled( appearanceConfig.kcfg_TrayIcon->isChecked() ); 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(); - //need to adjust button - adjustButtons(); } } else { delete mTrayIcon; mTrayIcon = 0; if ( mCloseAction ) { mCloseAction->setVisible( false ); } } show(); repaint(); } void KLineal::switchRelativeScale( bool checked ) { mRelativeScale = checked; mCenterOriginAction->setEnabled( !mRelativeScale ); mOffsetAction->setEnabled( !mRelativeScale ); repaint(); - adjustLabel(); saveSettings(); } /** * save the ruler color to the config file */ void KLineal::saveSettings() { RulerSettings::self()->setBgColor( mColor ); RulerSettings::self()->setScaleFont( mScaleFont ); - RulerSettings::self()->setLength( mLongEdgeLen ); - RulerSettings::self()->setOrientation( mOrientation ); + 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(); } -void KLineal::copyColor() -{ - QApplication::clipboard()->setText( mColorLabel->text() ); -} - /** * lets the context menu appear at current cursor position */ void KLineal::showMenu() { QPoint pos = QCursor::pos(); mMenu->popup( pos ); } -/** - * overwritten to switch the value label and line cursor on - */ -void KLineal::enterEvent( QEvent *inEvent ) +bool KLineal::isResizing() const { - Q_UNUSED( inEvent ); - - if ( !mDragging ) { - showLabel(); - } + return mouseGrabber() == this && ( mRulerState == StateBegin || mRulerState == StateEnd ); } -/** - * overwritten to switch the value label and line cursor off - */ -void KLineal::leaveEvent( QEvent *inEvent ) +int KLineal::length() const { - Q_UNUSED( inEvent ); - - if ( !geometry().contains( QCursor::pos() ) ) { - hideLabel(); - } + return mHorizontal ? width() : height(); } -/** - * shows the value lable - */ -void KLineal::showLabel() +QPoint KLineal::localCursorPos() const { - adjustLabel(); - mLabel->show(); - mColorLabel->show(); - if ( RulerSettings::self()->rotateButtonsVisible() ) { - mBtnRotateLeft->show(); - mBtnRotateRight->show(); - } - if ( mCloseButton && - RulerSettings::self()->closeButtonVisible() && - RulerSettings::self()->trayIcon()) { - mCloseButton->show(); - } + // 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(); } -/** - * hides the value label - */ -void KLineal::hideLabel() +QString KLineal::indicatorText() const { - mLabel->hide(); - mColorLabel->hide(); - mBtnRotateLeft->hide(); - mBtnRotateRight->hide(); - if ( mCloseButton ) { - mCloseButton->hide(); - } -} - -/** - * updates the current value label - */ -void KLineal::adjustLabel() -{ - QString s; - QPoint cpos = QCursor::pos(); - - int digit = ( mOrientation == North || mOrientation == South ) ? cpos.x() - x() : cpos.y() - y(); - + int xy = mHorizontal ? localCursorPos().x() : localCursorPos().y(); if ( !mRelativeScale ) { - if ( mLeftToRight ) { - digit += mOffset; - } else { - digit = mLongEdgeLen - digit + mOffset; - } + int len = mLeftToRight ? xy + 1 : length() - xy; + return i18n( "%1 px", len ); } else { - // INFO: Perhaps use float also for displaying relative value - digit = (int)( ( digit * 100.f ) / mLongEdgeLen ); + int len = ( xy * 100.f ) / length(); if ( !mLeftToRight ) { - digit = 100 - digit; + len = 100 - len; } - } - - s.sprintf( "%d%s", digit, ( mRelativeScale ? "%" : " px" ) ); - mLabel->setText( s ); -} - -/** - * Updates the position of the tool buttons - */ -void KLineal::adjustButtons() -{ - switch( mOrientation ) { - case North: - mBtnRotateLeft->move( mLongEdgeLen / 2 - 28, height() - 31 ); - mBtnRotateRight->move( mLongEdgeLen / 2 + 2, height() - 31 ); - if ( mCloseButton ) { - mCloseButton->move( width() - 31, height() - 31 ); - } - break; - - case South: - mBtnRotateLeft->move( mLongEdgeLen / 2 - 28, 5 ); - mBtnRotateRight->move( mLongEdgeLen / 2 + 2, 5 ); - if ( mCloseButton ) { - mCloseButton->move( width() - 31, 5 ); - } - break; - - case East: - mBtnRotateLeft->move( 5, mLongEdgeLen / 2 - 28 ); - mBtnRotateRight->move( 5, mLongEdgeLen / 2 + 2 ); - if ( mCloseButton ) { - mCloseButton->move( 5, height() - 31 ); - } - break; - - case West: - mBtnRotateLeft->move( width() - 31, mLongEdgeLen / 2 - 28 ); - mBtnRotateRight->move( width() - 31, mLongEdgeLen / 2 + 2 ); - if ( mCloseButton ) { - mCloseButton->move( width() - 31, height() - 31 ); - } - break; + 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; } move( pos() + dist ); KNotification::event( QString(), QStringLiteral( "cursormove" ), QString() ); } -/** - * overwritten to handle the line cursor which is a separate widget outside the main - * window. Also used for dragging. - */ +void KLineal::leaveEvent( QEvent *e ) +{ + Q_UNUSED( e ); + update(); +} + void KLineal::mouseMoveEvent( QMouseEvent *inEvent ) { Q_UNUSED( inEvent ); - if ( mDragging && this == mouseGrabber() ) { -#ifdef KRULER_HAVE_X11 - if ( !QX11Info::isPlatformX11() || !RulerSettings::self()->nativeMoving() ) { -#endif + if ( mRulerState >= StateMove ) { + if ( mouseGrabber() != this ) { + return; + } + if ( mRulerState == StateMove ) { move( QCursor::pos() - mDragOffset ); -#ifdef KRULER_HAVE_X11 + } 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 ); } -#endif } else { - QPoint p = QCursor::pos(); - - switch ( mOrientation ) { - case North: - p.setY( p.y() - 46 ); - break; - - case East: - p.setX( p.x() + 46 ); - break; - - case West: - p.setX( p.x() - 46 ); - break; - - case South: - p.setY( p.y() + 46 ); - break; - } - - QColor color = pixelColor( p ); - int h, s, v; - color.getHsv( &h, &s, &v ); - mColorLabel->setText( color.name().toUpper() ); - QPalette palette = mColorLabel->palette(); - palette.setColor( mColorLabel->backgroundRole(), color ); - if ( v < 255 / 2 ) { - v = 255; + QPoint cpos = localCursorPos(); + mRulerState = StateNone; + if ( beginRect().contains( cpos ) || endRect().contains( cpos) ) { + setCursor( resizeCursor() ); } else { - v = 0; + setCursor( mCrossCursor ); } - color.setHsv( h, s, v ); - palette.setColor( mColorLabel->foregroundRole(), color ); - mColorLabel->setPalette( palette ); - adjustLabel(); + update(); } } /** * overwritten for dragging and context menu */ void KLineal::mousePressEvent( QMouseEvent *inEvent ) { mLastClickPos = QCursor::pos(); - hideLabel(); QRect gr = geometry(); - mDragOffset = mLastClickPos - QPoint( gr.left(), gr.top() ); + mDragOffset = mLastClickPos - gr.topLeft(); if ( inEvent->button() == Qt::LeftButton ) { -#ifdef KRULER_HAVE_X11 - if ( QX11Info::isPlatformX11() && RulerSettings::self()->nativeMoving() ) { - xcb_ungrab_pointer( QX11Info::connection(), QX11Info::appTime() ); - NETRootInfo wm_root( QX11Info::connection(), NET::WMMoveResize ); - wm_root.moveResizeRequest( winId(), inEvent->globalX(), inEvent->globalY(), NET::Move ); - } else { -#endif - if ( !mDragging ) { - grabMouse( Qt::SizeAllCursor ); - mDragging = true; + 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 ); + } } -#ifdef KRULER_HAVE_X11 } -#endif } else if ( inEvent->button() == Qt::MidButton ) { mClicked = true; - turnLeft(); + 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 ) { - Q_UNUSED( inEvent ); - -#ifdef KRULER_HAVE_X11 - if ( QX11Info::isPlatformX11() && RulerSettings::self()->nativeMoving() ) { - NETRootInfo wm_root( QX11Info::connection(), NET::WMMoveResize ); - wm_root.moveResizeRequest( winId(), inEvent->globalX(), inEvent->globalY(), NET::MoveResizeCancel ); - } else { -#endif - if ( mDragging ) { - mDragging = false; - releaseMouse(); - } -#ifdef KRULER_HAVE_X11 + if ( mRulerState != StateNone ) { + mRulerState = StateNone; + releaseMouse(); + saveSettings(); + } else if ( nativeMove() ) { + stopNativeMove( inEvent ); } -#endif - - showLabel(); } void KLineal::wheelEvent( QWheelEvent *e ) { int numDegrees = e->delta() / 8; int numSteps = numDegrees / 15; // changing offset if ( e->buttons() == Qt::LeftButton ) { if ( !mRelativeScale ) { - mLabel->show(); mOffset += numSteps; repaint(); - mLabel->setText( i18n( "Offset: %1", mOffset ) ); saveSettings(); } - } else { // changing length - int oldLen = mLongEdgeLen; - int newLength = mLongEdgeLen + numSteps; - reLengthAbsolute( newLength ); - mLabel->setText( i18n( "Length: %1 px", mLongEdgeLen ) ); - - // when holding shift relength at the other side - if ( e->modifiers() & Qt::ShiftModifier ) { - int change = mLongEdgeLen - oldLen; - - QPoint dist; - - if ( mOrientation == North || mOrientation == South ) { - dist.setX( -change ); - } else { - dist.setY( -change ); - } - - move( pos() + dist ); - } } 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 ); - QFontMetrics metrics = painter.fontMetrics(); - int longLen; - int shortStart; - int w = width(); - int h = height(); - - // draw a frame around the whole thing - // (for some unknown reason, this doesn't show up anymore) - switch ( mOrientation ) { - case North: - default: - shortStart = 0; - longLen = w; - painter.drawLine( 0, 0, 0, h - 1 ); - painter.drawLine( 0, h - 1, w - 1, h - 1 ); - painter.drawLine( w - 1, h - 1, w - 1, 0 ); - break; - - case East: - shortStart = w; - longLen = h; - painter.drawLine( 0, 0, 0, h - 1 ); - painter.drawLine( 0, h - 1, w - 1, h - 1 ); - painter.drawLine( w - 1, 0, 0, 0 ); - break; - - case South: - shortStart = h; - longLen = w; - painter.drawLine( 0, 0, 0, h - 1 ); - painter.drawLine( w - 1, h - 1, w - 1, 0 ); - painter.drawLine( w - 1, 0, 0, 0 ); - break; - - case West: - shortStart = 0; - longLen = h; - painter.drawLine( 0, h - 1, w - 1, h - 1 ); - painter.drawLine( w - 1, h - 1, w - 1, 0 ); - painter.drawLine( w - 1, 0, 0, 0 ); - break; - } + int longLen = length(); if ( !mRelativeScale ) { int digit; int len; - for ( int x = 0; x < longLen; ++x ) { + // 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; - len = 6; - - if ( digit % 10 == 0 ) len = 10; - if ( digit % 20 == 0 ) len = 15; - if ( digit % 100 == 0 ) len = 18; + 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 % 20 == 0 ) { - font.setBold( digit % 100 == 0 ); - painter.setFont( font ); + if ( digit % 100 == 0 && digit != 0 ) { QString units; units.sprintf( "%d", digit ); - QSize textSize = metrics.size( Qt::TextSingleLine, units ); - int tw = textSize.width(); - int th = textSize.height(); - - switch ( mOrientation ) { - case North: - painter.drawText( x - tw / 2, shortStart + len + th, units ); - break; - - case South: - painter.drawText( x - tw / 2, shortStart - len - 2, units ); - break; - - case East: - painter.drawText( shortStart - len - tw - 2, x + th / 2 - 2, units ); - break; - - case West: - painter.drawText( shortStart + len + 2, x + th / 2 - 2, units ); - break; - } + drawScaleText( painter, x, units ); } - switch( mOrientation ) { - case North: - painter.drawLine( x, shortStart, x, shortStart + len ); - break; - case South: - painter.drawLine( x, shortStart, x, shortStart - len ); - break; - case East: - painter.drawLine( shortStart, x, shortStart - len, x ); - break; - case West: - painter.drawLine( shortStart, x, shortStart + len, x ); - break; - } + drawScaleTick( painter, x, len ); } } else { float step = longLen / 100.f; int len; - font.setBold( true ); - painter.setFont( font ); - for ( int i = 0; i <= 100; ++i ) { int x = (int)( i * step ); - len = ( i % 10 ) ? 6 : 15; - if ( i % 10 == 0 ) { + if ( i % 10 == 0 && i != 0 && i != 100 ) { QString units; int value = mLeftToRight ? i : ( 100 - i ); units.sprintf( "%d%%", value ); - QSize textSize = metrics.size( Qt::TextSingleLine, units ); - int tw = textSize.width(); - int th = textSize.height(); - - switch ( mOrientation ) { - case North: - painter.drawText( x - tw / 2, shortStart + len + th, units ); - break; - - case South: - painter.drawText( x - tw / 2, shortStart - len - 2, units ); - break; - - case East: - painter.drawText( shortStart - len - tw - 2, x + th / 2 - 2, units ); - break; - - case West: - painter.drawText( shortStart + len + 2, x + th / 2 - 2, units ); - break; - } + drawScaleText( painter, x, units ); + len = MEDIUM2_TICK_SIZE; + } else { + len = SMALL_TICK_SIZE; } - switch( mOrientation ) { - case North: - painter.drawLine( x, shortStart, x, shortStart + len ); - break; - case South: - painter.drawLine( x, shortStart, x, shortStart - len ); - break; - case East: - painter.drawLine( shortStart, x, shortStart - len, x ); - break; - case West: - painter.drawLine( shortStart, x, shortStart + len, x ); - break; - } + 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.width( text ); + 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 ); -} -QColor KLineal::pixelColor(const QPoint &p) -{ - const QDesktopWidget *desktop = QApplication::desktop(); - QScreen *screen = QGuiApplication::screens().at(desktop->screenNumber()); - const QPixmap pixmap = screen->grabWindow(desktop->winId(), p.x(), p.y(), 1, 1); - return QColor(pixmap.toImage().pixel(QPoint(0, 0))); + 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 ); + } } - diff --git a/klineal.h b/klineal.h index ef75632..efea641 100644 --- a/klineal.h +++ b/klineal.h @@ -1,135 +1,127 @@ /*************************************************************************** klineal.h - description ------------------- begin : Fri Oct 13 2000 Copyright : (C) 2000 - 2008 by Till Krech (C) 2009 by Mathias Soeken + (C) 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. * * * ***************************************************************************/ #ifndef KLINEAL_H #define KLINEAL_H #include class QAction; -class QAutoSizeLabel; class QIcon; class QMenu; class QToolButton; class KActionCollection; class KRulerSystemTray; class KLineal : public QWidget { Q_OBJECT public: - enum { North = 0, West, South, East }; - KLineal( QWidget *parent = 0 ); ~KLineal(); void move( int x, int y ); void move( const QPoint &p ); QPoint pos() const; int x() const; int y() const; protected: void keyPressEvent( QKeyEvent *e ); + void leaveEvent( QEvent *e ); void mousePressEvent( QMouseEvent *e ); void mouseReleaseEvent( QMouseEvent *e ); void mouseMoveEvent( QMouseEvent *e ); void wheelEvent( QWheelEvent *e ); void paintEvent( QPaintEvent *e ); - void enterEvent( QEvent *e ); - void leaveEvent( QEvent *e ); void createSystemTray(); private: + void createCrossCursor(); QAction* addAction( QMenu *menu, const QIcon& icon, const QString& text, const QObject* receiver, const char* member, const QKeySequence &shortcut, const QString& name ); void drawScale( QPainter &painter ); void drawBackground( QPainter &painter ); - void reLength( int percentOfScreen ); - void reLengthAbsolute( int length ); + void drawScaleText( QPainter &painter, int x, const QString &text ); + void drawScaleTick( QPainter &painter, int x, int length ); + void drawResizeHandle( QPainter &painter, Qt::Edge edge ); + void drawIndicatorOverlay( QPainter &painter, int xy ); + void drawIndicatorText( QPainter &painter, int xy ); void updateScaleDirectionMenuItem(); - QColor pixelColor( const QPoint &p ); - bool mDragging; + QRect beginRect() const; + QRect midRect() const; + QRect endRect() const; + Qt::CursorShape resizeCursor() const; + bool nativeMove() const; + void startNativeMove( QMouseEvent *e ); + void stopNativeMove( QMouseEvent *e ); + QString indicatorText() const; + + enum RulerState { + StateNone, + StateMove, + StateBegin, + StateEnd + }; + QCursor mCrossCursor; + RulerState mRulerState; QPoint mLastClickPos; QPoint mDragOffset; - QAutoSizeLabel *mLabel; - QAutoSizeLabel *mColorLabel; - int mOrientation; - int mLongEdgeLen; - int mShortEdgeLen; + bool mHorizontal; QMenu *mMenu; QAction *mCloseAction; - QMenu *mLenMenu; - QAction *mFullScreenAction; QAction *mScaleDirectionAction; QAction *mCenterOriginAction; QAction *mOffsetAction; QColor mColor; - QCursor mCurrentCursor; - QCursor mNorthCursor; - QCursor mEastCursor; - QCursor mWestCursor; - QCursor mSouthCursor; - QCursor mDragCursor; QFont mScaleFont; bool mAlwaysOnTopLayer; bool mClicked; bool mLeftToRight; int mOffset; bool mRelativeScale; KActionCollection *mActionCollection; int mOpacity; - QToolButton *mBtnRotateLeft, *mBtnRotateRight; - QToolButton *mCloseButton; KRulerSystemTray *mTrayIcon; + void setHorizontal( bool horizontal ); + + bool isResizing() const; + int length() const; + QPoint localCursorPos() const; + public slots: - void setOrientation( int ); - void setNorth(); - void setEast(); - void setSouth(); - void setWest(); - void turnLeft(); - void turnRight(); + void rotate(); void showMenu(); - void hideLabel(); - void showLabel(); - void adjustLabel(); - void adjustButtons(); - void setShortLength(); - void setMediumLength(); - void setTallLength(); - void setFullLength(); void switchDirection(); void centerOrigin(); void slotOffset(); - void slotLength(); void slotOpacity( int value ); void slotKeyBindings(); void slotPreferences(); void switchRelativeScale( bool checked ); - void copyColor(); void saveSettings(); void slotClose(); void slotQuit(); void loadConfig(); }; #endif diff --git a/kruler.kcfg b/kruler.kcfg index c51ae61..efcb870 100644 --- a/kruler.kcfg +++ b/kruler.kcfg @@ -1,60 +1,52 @@ QFontDatabase QColor(255, 200, 80) 600 QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont) - - - 2 + + + true true 0 false false 255 - - - false - - - - false - false true diff --git a/qautosizelabel.cpp b/qautosizelabel.cpp deleted file mode 100644 index 2b98349..0000000 --- a/qautosizelabel.cpp +++ /dev/null @@ -1,53 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// // -// Copyright (C) 2008 Mathias Soeken // -// // -// 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 "qautosizelabel.h" - -#include - -QAutoSizeLabel::QAutoSizeLabel( QWidget *parent, Qt::WindowFlags f ) - : QLabel( parent, f ) -{ - resize(); -} - -QAutoSizeLabel::QAutoSizeLabel( const QString &text, QWidget *parent, Qt::WindowFlags f ) - : QLabel( text, parent, f ) -{ - resize(); -} - -QAutoSizeLabel::~QAutoSizeLabel() -{ -} - -void QAutoSizeLabel::setText( const QString &text ) -{ - QLabel::setText( text ); - resize(); -} - -void QAutoSizeLabel::resize() -{ - QFontMetrics fm( font(), this ); - QLabel::resize( fm.size( Qt::TextSingleLine, text() ) ); -} - - diff --git a/qautosizelabel.h b/qautosizelabel.h deleted file mode 100644 index ce65470..0000000 --- a/qautosizelabel.h +++ /dev/null @@ -1,41 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// // -// Copyright (C) 2008 Mathias Soeken // -// // -// 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. // -//////////////////////////////////////////////////////////////////////////// - -#ifndef QAUTOSIZELABEL_H -#define QAUTOSIZELABEL_H - -#include - -class QAutoSizeLabel : public QLabel { - Q_OBJECT - - public: - explicit QAutoSizeLabel( QWidget *parent = 0, Qt::WindowFlags f = 0 ); - explicit QAutoSizeLabel( const QString &text, QWidget *parent = 0, Qt::WindowFlags f = 0 ); - virtual ~QAutoSizeLabel(); - - public Q_SLOTS: - void setText( const QString &text ); - - private: - void resize(); -}; - -#endif