various fixes:
[kdegraphics.git] / kruler / klineal.cpp
blob2fa4d237b1fe4721aabdff73515fce68b93e35aa
1 /***************************************************************************
2 klineal.cpp - description
3 -------------------
4 Begin : Fri Oct 13 2000
5 Copyright : 2000 by Till Krech <till@snafu.de>
6 2008 by Mathias Soeken <msoeken@informatik.uni-bremen.de>
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include "klineal.h"
20 #include <QBitmap>
21 #include <QBrush>
22 #include <QClipboard>
23 #include <QPainter>
24 #include <QMouseEvent>
25 #include <QSlider>
26 #include <QToolButton>
27 #include <QWidgetAction>
29 #include <KAction>
30 #include <KActionCollection>
31 #include <KColorDialog>
32 #include <KConfig>
33 #include <KConfigDialog>
34 #include <KGlobalSettings>
35 #include <KHelpMenu>
36 #include <KInputDialog>
37 #include <KLocale>
38 #include <KMenu>
39 #include <KNotification>
40 #include <KShortcutsDialog>
41 #include <KStandardAction>
42 #include <KSystemTrayIcon>
43 #include <KToolInvocation>
44 #include <KWindowSystem>
45 #include <KApplication>
47 #include <netwm.h>
49 #include "kruler.h"
50 #include "qautosizelabel.h"
52 #include "ui_cfg_appearance.h"
53 #include "ui_cfg_advanced.h"
55 /**
56 * this is our cursor bitmap:
57 * a line 48 pixels long with an arrow pointing down
58 * and a sqare with a one pixel hole at the top (end)
60 static const uchar cursorBits[] = {
61 0x38, 0x28, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10,
62 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
63 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
64 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
65 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
66 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10,
69 /**
70 * create the thingy with no borders and set up
71 * its members
73 KLineal::KLineal( QWidget *parent )
74 : QWidget( parent ),
75 mDragging( false ),
76 mShortEdgeLen( 70 ),
77 mLenMenu( 0 ), // INFO This member could be eventually deleted
78 // since if mFullScreenAction is initialized
79 // mLenMenu should have been, too.
80 mFullScreenAction( 0 ),
81 mScaleDirectionAction( 0 ),
82 mCenterOriginAction( 0 ),
83 mOffsetAction( 0 ),
84 mClicked( false ),
85 mActionCollection( 0 ),
86 mCloseButton( 0 )
88 KWindowSystem::setType( winId(), NET::Override ); // or NET::Normal
89 KWindowSystem::setState( winId(), NET::KeepAbove );
91 setAttribute( Qt::WA_TranslucentBackground );
92 setWindowFlags( Qt::FramelessWindowHint );
94 setMinimumSize( 60, 60 );
95 setMaximumSize( 8000, 8000 );
96 setWhatsThis( i18n( "This is a tool to measure pixel distances and colors on the screen. "
97 "It is useful for working on layouts of dialogs, web pages etc." ) );
98 setMouseTracking( true );
100 QBitmap bim = QBitmap::fromData( QSize( 8, 48 ), cursorBits, QImage::Format_Mono );
101 QMatrix m;
102 m.rotate( 90.0 );
103 mNorthCursor = QCursor( bim, bim, 3, 47 );
104 bim = bim.transformed( m );
105 mEastCursor = QCursor( bim, bim, 0, 3 );
106 bim = bim.transformed( m );
107 mSouthCursor = QCursor( bim, bim, 4, 0 );
108 bim = bim.transformed( m );
109 mWestCursor = QCursor( bim, bim, 47, 4 );
111 mCurrentCursor = mNorthCursor;
112 mColor = RulerSettings::self()->bgColor();
113 mScaleFont = RulerSettings::self()->scaleFont();
114 mLongEdgeLen = RulerSettings::self()->length();
115 mOrientation = RulerSettings::self()->orientation();
116 mLeftToRight = RulerSettings::self()->leftToRight();
117 mOffset = RulerSettings::self()->offset();
118 mRelativeScale = RulerSettings::self()->relativeScale();
120 mLabel = new QAutoSizeLabel( this );
121 mLabel->setGeometry( 0, height() - 12, 32, 12 );
122 QFont labelFont( KGlobalSettings::generalFont().family(), 10 );
123 labelFont.setPixelSize( 10 );
124 mLabel->setFont( labelFont );
125 mLabel->setWhatsThis( i18n( "This is the current distance measured in pixels." ) );
126 mColorLabel = new QAutoSizeLabel( this );
127 mColorLabel->setAutoFillBackground( true );
128 QFont colorFont( KGlobalSettings::fixedFont().family(), 10 );
129 colorFont.setPixelSize( 10 );
130 mColorLabel->setFont( colorFont );
131 mColorLabel->move( mLabel->pos() + QPoint(0, 20) );
132 mColorLabel->setWhatsThis(i18n("This is the current color in hexadecimal rgb representation"
133 " as you may use it in HTML or as a QColor name. "
134 "The rectangles background shows the color of the pixel inside the "
135 "little square at the end of the line cursor." ) );
137 mBtnRotateLeft = new QToolButton( this );
138 mBtnRotateLeft->setIcon( KIcon( "object-rotate-left" ) );
139 mBtnRotateLeft->setToolTip( i18n( "Turn Left" ) );
140 connect( mBtnRotateLeft, SIGNAL( clicked() ), this, SLOT( turnLeft() ) );
142 mBtnRotateRight = new QToolButton( this );
143 mBtnRotateRight->setIcon( KIcon( "object-rotate-right" ) );
144 mBtnRotateRight->setToolTip( i18n( "Turn Right" ) );
145 connect( mBtnRotateRight, SIGNAL( clicked() ), this, SLOT( turnRight() ) );
147 resize( QSize( mLongEdgeLen, mShortEdgeLen ) );
149 //BEGIN setup menu and actions
150 mActionCollection = new KActionCollection( this );
151 mActionCollection->setConfigGroup( "Actions" );
153 mMenu = new KMenu( this );
154 mMenu->addTitle( i18n( "KRuler" ) );
155 KMenu *oriMenu = new KMenu( i18n( "&Orientation"), this );
156 addAction( oriMenu, KIcon( "kruler-north" ), i18nc( "Turn Kruler North", "&North" ),
157 this, SLOT( setNorth() ), Qt::Key_N, "turn_north" );
158 addAction( oriMenu, KIcon( "kruler-east" ), i18nc( "Turn Kruler East", "&East" ),
159 this, SLOT( setEast() ), Qt::Key_E, "turn_east" );
160 addAction( oriMenu, KIcon( "kruler-south" ), i18nc( "Turn Kruler South", "&South" ),
161 this, SLOT( setSouth() ), Qt::Key_S, "turn_south" );
162 addAction( oriMenu, KIcon( "kruler-west" ), i18nc( "Turn Kruler West", "&West" ),
163 this, SLOT( setWest() ), Qt::Key_W, "turn_west" );
164 addAction( oriMenu, KIcon( "object-rotate-right" ), i18n( "&Turn Right" ),
165 this, SLOT( turnRight() ), Qt::Key_R, "turn_right" );
166 addAction( oriMenu, KIcon( "object-rotate-left" ), i18n( "Turn &Left" ),
167 this, SLOT( turnLeft() ), Qt::Key_L, "turn_left" );
168 mMenu->addMenu( oriMenu );
170 mLenMenu = new KMenu( i18n( "&Length" ), this );
171 addAction( mLenMenu, KIcon(), i18nc( "Make Kruler Height Short", "&Short" ),
172 this, SLOT( setShortLength() ), Qt::CTRL + Qt::Key_S, "length_short" );
173 addAction( mLenMenu, KIcon(), i18nc( "Make Kruler Height Medium", "&Medium" ),
174 this, SLOT( setMediumLength() ), Qt::CTRL + Qt::Key_M, "length_medium" );
175 addAction( mLenMenu, KIcon(), i18nc( "Make Kruler Height Tall", "&Tall" ),
176 this, SLOT( setTallLength() ), Qt::CTRL + Qt::Key_T, "length_tall" );
177 addAction( mLenMenu, KIcon(), i18n("&Full Screen Width"),
178 this, SLOT( setFullLength() ), Qt::CTRL + Qt::Key_F, "length_full_length" );
179 mLenMenu->addSeparator();
180 addAction( mLenMenu, KIcon(), i18n( "Length..." ),
181 this, SLOT( slotLength() ), QKeySequence(), "set_length" );
182 mMenu->addMenu( mLenMenu );
184 KMenu* scaleMenu = new KMenu( i18n( "&Scale" ), this );
185 mScaleDirectionAction = addAction( scaleMenu, KIcon(), i18n( "Right To Left" ),
186 this, SLOT( switchDirection() ), Qt::Key_D, "right_to_left" );
187 mCenterOriginAction = addAction( scaleMenu, KIcon(), i18n( "Center origin" ),
188 this, SLOT( centerOrigin() ), Qt::Key_C, "center_origin" );
189 mCenterOriginAction->setEnabled( !mRelativeScale );
190 mOffsetAction = addAction( scaleMenu, KIcon(), i18n( "Offset..." ),
191 this, SLOT( slotOffset() ), Qt::Key_O, "set_offset" );
192 mOffsetAction->setEnabled( !mRelativeScale );
193 scaleMenu->addSeparator();
194 KAction *relativeScaleAction = addAction( scaleMenu, KIcon(), i18n( "Percentage" ),
195 0, 0, QKeySequence(), "toggle_percentage" );
196 relativeScaleAction->setCheckable( true );
197 relativeScaleAction->setChecked( mRelativeScale );
198 connect( relativeScaleAction, SIGNAL( toggled( bool ) ), this, SLOT( switchRelativeScale( bool ) ) );
199 mMenu->addMenu( scaleMenu );
201 mOpacity = RulerSettings::self()->opacity();
202 KMenu* opacityMenu = new KMenu( i18n( "O&pacity" ), this );
203 QWidgetAction *opacityAction = new QWidgetAction( this );
204 QSlider *slider = new QSlider( this );
205 slider->setMinimum( 0 );
206 slider->setMaximum( 255 );
207 slider->setSingleStep( 1 );
208 slider->setOrientation( Qt::Horizontal );
209 slider->setValue( RulerSettings::self()->opacity() );
210 connect( slider, SIGNAL( valueChanged( int ) ), this, SLOT( slotOpacity( int ) ) );
211 opacityAction->setDefaultWidget( slider );
212 opacityMenu->addAction( opacityAction );
213 mMenu->addMenu( opacityMenu );
215 KAction *keyBindings = KStandardAction::keyBindings( this, SLOT( slotKeyBindings() ), this );
216 mActionCollection->addAction( "key_bindings", keyBindings );
217 mMenu->addAction( keyBindings );
218 KAction *preferences = KStandardAction::preferences( this, SLOT( slotPreferences() ), this );
219 mActionCollection->addAction( "preferences", preferences );
220 mMenu->addAction( preferences );
221 mMenu->addSeparator();
222 KAction *copyColorAction = KStandardAction::copy( this, SLOT( copyColor() ), this );
223 copyColorAction->setText( i18n( "Copy Color" ) );
224 mActionCollection->addAction( "copy_color", copyColorAction );
225 mMenu->addAction( copyColorAction );
226 mMenu->addSeparator();
227 mMenu->addMenu( ( new KHelpMenu( this, KGlobal::mainComponent().aboutData(), true ) )->menu() );
228 mMenu->addSeparator();
230 if ( RulerSettings::self()->trayIcon() ) {
231 KAction *closeAction = KStandardAction::close( this, SLOT( slotClose() ), this );
232 mActionCollection->addAction( "close", closeAction );
233 mMenu->addAction( closeAction );
235 mCloseButton = new QToolButton( this );
236 mCloseButton->setIcon( closeAction->icon() );
237 mCloseButton->setToolTip( closeAction->text().remove( '&' ) );
238 connect( mCloseButton, SIGNAL( clicked() ), this, SLOT( slotClose() ) );
241 KAction *quit = KStandardAction::quit( kapp, SLOT( quit() ), this );
242 mActionCollection->addAction( "quit", quit );
243 mMenu->addAction( quit );
245 mActionCollection->associateWidget( this );
246 mActionCollection->readSettings();
248 mLastClickPos = geometry().topLeft() + QPoint( width() / 2, height() / 2 );
250 hideLabel();
251 setOrientation( mOrientation );
253 if ( RulerSettings::self()->trayIcon() ) {
254 KSystemTrayIcon *tray = new KSystemTrayIcon( KIcon( "kruler" ), this );
255 tray->show();
259 KLineal::~KLineal()
263 KAction* KLineal::addAction( KMenu *menu, KIcon icon, const QString& text,
264 const QObject* receiver, const char* member,
265 const QKeySequence &shortcut, const QString& name )
267 KAction *action = new KAction( icon, text, mActionCollection );
268 action->setShortcut( shortcut );
269 if ( receiver ) {
270 connect( action, SIGNAL( triggered() ), receiver, member );
272 menu->addAction( action );
273 mActionCollection->addAction( name, action );
274 return action;
277 void KLineal::slotClose()
279 hide();
282 void KLineal::slotQuit()
284 kapp->quit();
287 void KLineal::move( int x, int y )
289 move( QPoint( x, y ) );
292 void KLineal::move(const QPoint &p)
294 setGeometry( QRect( p, size() ) );
297 QPoint KLineal::pos()
299 return frameGeometry().topLeft();
302 int KLineal::x()
304 return pos().x();
307 int KLineal::y()
309 return pos().y();
312 void KLineal::drawBackground( QPainter& painter )
314 QColor a, b, bg = mColor;
315 QLinearGradient gradient;
316 switch ( mOrientation ) {
317 case North:
318 a = bg.light( 120 );
319 b = bg.dark( 130 );
320 gradient = QLinearGradient( 1, 0, 1, height() );
321 break;
323 case South:
324 b = bg.light( 120 );
325 a = bg.dark( 130 );
326 gradient = QLinearGradient( 1, 0, 1, height() );
327 break;
329 case West:
330 a = bg.light( 120 );
331 b = bg.dark( 130 );
332 gradient = QLinearGradient( 0, 1, width(), 1 );
333 break;
335 case East:
336 b = bg.light( 120 );
337 a = bg.dark( 130 );
338 gradient = QLinearGradient( 0, 1, width(), 1 );
339 break;
341 a.setAlpha( mOpacity );
342 b.setAlpha( mOpacity );
343 gradient.setColorAt( 0, a );
344 gradient.setColorAt( 1, b );
345 painter.fillRect( rect(), QBrush( gradient ) );
348 void KLineal::setOrientation( int inOrientation )
350 QRect r = frameGeometry();
351 int nineties = (int)inOrientation - (int)mOrientation;
352 mOrientation = ( inOrientation + 4 ) % 4;
353 QPoint center = mLastClickPos, newTopLeft;
355 if ( mClicked ) {
356 center = mLastClickPos;
357 mClicked = false;
358 } else {
359 center = r.topLeft() + QPoint( width() / 2, height() / 2 );
362 if ( nineties % 2 ) {
363 newTopLeft = QPoint( center.x() - height() / 2, center.y() - width() / 2 );
364 } else {
365 newTopLeft = r.topLeft();
368 if ( mOrientation == North || mOrientation == South ) {
369 r.setSize( QSize( mLongEdgeLen, mShortEdgeLen ) );
370 } else {
371 r.setSize( QSize( mShortEdgeLen, mLongEdgeLen ) );
374 r.moveTo(newTopLeft);
376 QRect desktop = KGlobalSettings::desktopGeometry( this );
378 if ( r.top() < desktop.top() ) {
379 r.moveTop( desktop.top() );
382 if ( r.bottom() > desktop.bottom() ) {
383 r.moveBottom( desktop.bottom() );
386 if ( r.left() < desktop.left() ) {
387 r.moveLeft( desktop.left() );
390 if ( r.right() > desktop.right() ) {
391 r.moveRight( desktop.right() );
394 setGeometry( r );
395 switch( mOrientation ) {
396 case North:
397 mLabel->move( 4, height()-mLabel->height() - 4 );
398 mColorLabel->move( mLabel->pos() + QPoint( 0, -20 ) );
399 mCurrentCursor = mNorthCursor;
400 break;
402 case South:
403 mLabel->move( 4, 4 );
404 mColorLabel->move( mLabel->pos() + QPoint( 0, 20 ) );
405 mCurrentCursor = mSouthCursor;
406 break;
408 case East:
409 mLabel->move( 4, 4 );
410 mColorLabel->move( mLabel->pos() + QPoint( 0, 20 ) );
411 mCurrentCursor = mEastCursor;
412 break;
414 case West:
415 mLabel->move( width()-mLabel->width() - 4, 4 );
416 mColorLabel->move( mLabel->pos() + QPoint( -5, 20 ) );
417 mCurrentCursor = mWestCursor;
418 break;
421 adjustButtons();
423 if ( mLenMenu && mFullScreenAction ) {
424 mFullScreenAction->setText( mOrientation % 2 ? i18n( "&Full Screen Height" ) : i18n( "&Full Screen Width" ) );
427 updateScaleDirectionMenuItem();
429 setCursor( mCurrentCursor );
430 repaint();
431 saveSettings();
434 void KLineal::setNorth()
436 setOrientation( North );
439 void KLineal::setEast()
441 setOrientation( East );
444 void KLineal::setSouth()
446 setOrientation( South );
449 void KLineal::setWest()
451 setOrientation( West );
454 void KLineal::turnRight()
456 setOrientation( mOrientation - 1 );
459 void KLineal::turnLeft()
461 setOrientation( mOrientation + 1 );
464 void KLineal::reLength( int percentOfScreen )
466 if ( percentOfScreen < 10 ) {
467 return;
470 QRect r = KGlobalSettings::desktopGeometry( this );
472 if ( mOrientation == North || mOrientation == South ) {
473 mLongEdgeLen = r.width() * percentOfScreen / 100;
474 resize( mLongEdgeLen, height() );
475 } else {
476 mLongEdgeLen = r.height() * percentOfScreen / 100;
477 resize( width(), mLongEdgeLen );
480 if ( x() + width() < 10 ) {
481 move( 10, y() );
484 if ( y() + height() < 10 ) {
485 move( x(), 10 );
488 adjustButtons();
489 saveSettings();
492 void KLineal::reLengthAbsolute( int length )
494 if ( length < 100 ) {
495 return;
498 QRect r = KGlobalSettings::desktopGeometry( this );
500 mLongEdgeLen = length;
501 if ( mOrientation == North || mOrientation == South ) {
502 resize( mLongEdgeLen, height() );
503 } else {
504 resize( width(), mLongEdgeLen );
507 if ( x() + width() < 10 ) {
508 move( 10, y() );
511 if ( y() + height() < 10 ) {
512 move( x(), 10 );
515 adjustButtons();
516 saveSettings();
519 void KLineal::updateScaleDirectionMenuItem()
521 if ( !mScaleDirectionAction ) return;
523 QString label;
525 if ( mOrientation == North || mOrientation == South ) {
526 label = mLeftToRight ? i18n( "Right To Left" ) : i18n( "Left To Right" );
527 } else {
528 label = mLeftToRight ? i18n( "Bottom To Top" ) : i18n( "Top To Bottom" );
531 mScaleDirectionAction->setText( label );
534 void KLineal::setShortLength()
536 reLength( 30 );
539 void KLineal::setMediumLength()
541 reLength( 50 );
544 void KLineal::setTallLength()
546 reLength( 75 );
549 void KLineal::setFullLength()
551 reLength( 100 );
554 void KLineal::switchDirection()
556 mLeftToRight = !mLeftToRight;
557 updateScaleDirectionMenuItem();
558 repaint();
559 adjustLabel();
560 saveSettings();
563 void KLineal::centerOrigin()
565 mOffset = -( mLongEdgeLen / 2 );
566 repaint();
567 adjustLabel();
568 saveSettings();
571 void KLineal::slotOffset()
573 bool ok;
574 int newOffset = KInputDialog::getInteger( i18n( "Scale offset" ),
575 i18n( "Offset:" ), mOffset,
576 -2147483647, 2147483647, 1, &ok, this );
578 if ( ok ) {
579 mOffset = newOffset;
580 repaint();
581 adjustLabel();
582 saveSettings();
586 void KLineal::slotLength()
588 bool ok;
589 QRect r = KGlobalSettings::desktopGeometry( this );
590 int width = ( ( mOrientation == North ) || ( mOrientation == South ) ) ? r.width() : r.height();
591 int newLength = KInputDialog::getInteger( i18n( "Ruler Length" ),
592 i18n( "Length:" ), mLongEdgeLen,
593 0, width, 1, &ok, this );
595 if ( ok ) {
596 reLengthAbsolute( newLength );
600 void KLineal::slotOpacity( int value )
602 mOpacity = value;
603 repaint();
604 RulerSettings::self()->setOpacity( value );
605 RulerSettings::self()->writeConfig();
608 void KLineal::slotKeyBindings()
610 KShortcutsDialog::configure( mActionCollection );
613 void KLineal::slotPreferences()
615 KConfigDialog *dialog = new KConfigDialog( this, "settings", RulerSettings::self() );
617 Ui::ConfigAppearance appearanceConfig;
618 QWidget *appearanceConfigWidget = new QWidget( dialog );
619 appearanceConfig.setupUi( appearanceConfigWidget );
620 appearanceConfig.kcfg_CloseButtonVisible->setEnabled( appearanceConfig.kcfg_TrayIcon->isChecked() );
621 dialog->addPage( appearanceConfigWidget, i18n( "Appearance" ), "preferences-desktop-default-applications" );
623 Ui::ConfigAdvanced advancedConfig;
624 QWidget *advancedConfigWidget = new QWidget( dialog );
625 advancedConfig.setupUi( advancedConfigWidget );
626 dialog->addPage( advancedConfigWidget, i18n( "Advanced" ), "preferences-other" );
628 dialog->exec();
629 mColor = RulerSettings::self()->bgColor();
630 mScaleFont = RulerSettings::self()->scaleFont();
631 repaint();
632 saveSettings();
635 void KLineal::switchRelativeScale( bool checked )
637 mRelativeScale = checked;
639 mCenterOriginAction->setEnabled( !mRelativeScale );
640 mOffsetAction->setEnabled( !mRelativeScale );
642 repaint();
643 adjustLabel();
644 saveSettings();
648 * save the ruler color to the config file
650 void KLineal::saveSettings()
652 RulerSettings::self()->setBgColor( mColor );
653 RulerSettings::self()->setScaleFont( mScaleFont );
654 RulerSettings::self()->setLength( mLongEdgeLen );
655 RulerSettings::self()->setOrientation( mOrientation );
656 RulerSettings::self()->setLeftToRight( mLeftToRight );
657 RulerSettings::self()->setOffset( mOffset );
658 RulerSettings::self()->setRelativeScale( mRelativeScale );
659 RulerSettings::self()->writeConfig();
662 void KLineal::copyColor()
664 QApplication::clipboard()->setText( mColorLabel->text() );
668 * lets the context menu appear at current cursor position
670 void KLineal::showMenu()
672 QPoint pos = QCursor::pos();
673 mMenu->popup( pos );
677 * overwritten to switch the value label and line cursor on
679 void KLineal::enterEvent( QEvent *inEvent )
681 Q_UNUSED( inEvent );
683 if ( !mDragging ) {
684 showLabel();
689 * overwritten to switch the value label and line cursor off
691 void KLineal::leaveEvent( QEvent *inEvent )
693 Q_UNUSED( inEvent );
695 if ( !geometry().contains( QCursor::pos() ) ) {
696 hideLabel();
701 * shows the value lable
703 void KLineal::showLabel()
705 adjustLabel();
706 mLabel->show();
707 mColorLabel->show();
708 if ( RulerSettings::self()->rotateButtonsVisible() ) {
709 mBtnRotateLeft->show();
710 mBtnRotateRight->show();
712 if ( mCloseButton && RulerSettings::self()->closeButtonVisible() ) {
713 mCloseButton->show();
718 * hides the value label
720 void KLineal::hideLabel()
722 mLabel->hide();
723 mColorLabel->hide();
724 mBtnRotateLeft->hide();
725 mBtnRotateRight->hide();
726 if ( mCloseButton ) {
727 mCloseButton->hide();
732 * updates the current value label
734 void KLineal::adjustLabel()
736 QString s;
737 QPoint cpos = QCursor::pos();
739 int digit = ( mOrientation == North || mOrientation == South ) ? cpos.x() - x() : cpos.y() - y();
741 if ( !mRelativeScale ) {
742 if ( mLeftToRight ) {
743 digit += mOffset;
744 } else {
745 digit = mLongEdgeLen - digit + mOffset;
747 } else {
748 // INFO: Perhaps use float also for displaying relative value
749 digit = (int)( ( digit * 100.f ) / mLongEdgeLen );
751 if ( !mLeftToRight ) {
752 digit = 100 - digit;
756 s.sprintf( "%d%s", digit, ( mRelativeScale ? "%" : " px" ) );
757 mLabel->setText( s );
761 * Updates the position of the tool buttons
763 void KLineal::adjustButtons()
765 switch( mOrientation ) {
766 case North:
767 mBtnRotateLeft->move( mLongEdgeLen / 2 - 28, height() - 31 );
768 mBtnRotateRight->move( mLongEdgeLen / 2 + 2, height() - 31 );
769 if ( mCloseButton ) {
770 mCloseButton->move( width() - 31, height() - 31 );
772 break;
774 case South:
775 mBtnRotateLeft->move( mLongEdgeLen / 2 - 28, 5 );
776 mBtnRotateRight->move( mLongEdgeLen / 2 + 2, 5 );
777 if ( mCloseButton ) {
778 mCloseButton->move( width() - 31, 5 );
780 break;
782 case East:
783 mBtnRotateLeft->move( 5, mLongEdgeLen / 2 - 28 );
784 mBtnRotateRight->move( 5, mLongEdgeLen / 2 + 2 );
785 if ( mCloseButton ) {
786 mCloseButton->move( 5, height() - 31 );
788 break;
790 case West:
791 mBtnRotateLeft->move( width() - 31, mLongEdgeLen / 2 - 28 );
792 mBtnRotateRight->move( width() - 31, mLongEdgeLen / 2 + 2 );
793 if ( mCloseButton ) {
794 mCloseButton->move( width() - 31, height() - 31 );
796 break;
800 void KLineal::keyPressEvent( QKeyEvent *e )
802 QPoint dist;
804 switch ( e->key() ) {
805 case Qt::Key_F1:
806 KToolInvocation::invokeHelp();
807 return;
809 case Qt::Key_Left:
810 dist.setX( -1 );
811 break;
813 case Qt::Key_Right:
814 dist.setX( 1 );
815 break;
817 case Qt::Key_Up:
818 dist.setY( -1 );
819 break;
821 case Qt::Key_Down:
822 dist.setY( 1 );
823 break;
825 default:
826 QWidget::keyPressEvent(e);
827 return;
830 if ( e->modifiers() & Qt::ShiftModifier ) {
831 dist *= 10;
834 move( pos() + dist );
835 KNotification::event( 0, "cursormove", QString() );
839 * overwritten to handle the line cursor which is a separate widget outside the main
840 * window. Also used for dragging.
842 void KLineal::mouseMoveEvent( QMouseEvent *inEvent )
844 Q_UNUSED( inEvent );
846 if ( mDragging && this == mouseGrabber() && !RulerSettings::self()->nativeMoving() ) {
847 move( QCursor::pos() - mDragOffset );
848 } else {
849 QPoint p = QCursor::pos();
851 switch (mOrientation) {
852 case North:
853 p.setY( p.y() - 46 );
854 break;
856 case East:
857 p.setX( p.x() + 46 );
858 break;
860 case West:
861 p.setX( p.x() - 46 );
862 break;
864 case South:
865 p.setY( p.y() + 46 );
866 break;
869 QColor color = KColorDialog::grabColor( p );
870 int h, s, v;
871 color.getHsv( &h, &s, &v );
872 mColorLabel->setText( color.name().toUpper() );
873 QPalette palette = mColorLabel->palette();
874 palette.setColor( mColorLabel->backgroundRole(), color );
875 if ( v < 255 / 2 ) {
876 v = 255;
877 } else {
878 v = 0;
880 color.setHsv( h, s, v );
881 palette.setColor( mColorLabel->foregroundRole(), color );
882 mColorLabel->setPalette( palette );
883 adjustLabel();
888 * overwritten for dragging and context menu
890 void KLineal::mousePressEvent( QMouseEvent *inEvent )
892 mLastClickPos = QCursor::pos();
893 hideLabel();
895 QRect gr = geometry();
896 mDragOffset = mLastClickPos - QPoint( gr.left(), gr.top() );
897 if ( inEvent->button() == Qt::LeftButton ) {
898 #ifdef Q_WS_X11
899 if ( RulerSettings::self()->nativeMoving() ) {
900 XUngrabPointer( QX11Info::display(), QX11Info::appTime() );
901 NETRootInfo wm_root( QX11Info::display(), NET::WMMoveResize );
902 wm_root.moveResizeRequest( winId(), inEvent->globalX(), inEvent->globalY(), NET::Move );
903 } else {
904 #endif
905 if ( !mDragging ) {
906 grabMouse( Qt::SizeAllCursor );
907 mDragging = true;
909 #ifdef Q_WS_X11
911 #endif
912 } else if ( inEvent->button() == Qt::MidButton ) {
913 mClicked = true;
914 turnLeft();
915 } else if ( inEvent->button() == Qt::RightButton ) {
916 showMenu();
921 * overwritten for dragging
923 void KLineal::mouseReleaseEvent( QMouseEvent *inEvent )
925 Q_UNUSED( inEvent );
927 #ifdef Q_WS_X11
928 if ( RulerSettings::self()->nativeMoving() ) {
929 NETRootInfo wm_root( QX11Info::display(), NET::WMMoveResize );
930 wm_root.moveResizeRequest( winId(), inEvent->globalX(), inEvent->globalY(), NET::MoveResizeCancel );
931 } else {
932 #endif
933 if ( mDragging ) {
934 mDragging = false;
935 releaseMouse();
937 #ifdef Q_WS_X11
939 #endif
941 showLabel();
944 void KLineal::wheelEvent( QWheelEvent *e )
946 int numDegrees = e->delta() / 8;
947 int numSteps = numDegrees / 15;
949 // changing offset
950 if ( e->buttons() == Qt::LeftButton ) {
951 if ( !mRelativeScale ) {
952 mLabel->show();
953 mOffset += numSteps;
955 repaint();
956 mLabel->setText( i18n( "Offset: %1", mOffset ) );
957 saveSettings();
959 } else { // changing length
960 int newLength = mLongEdgeLen + numSteps;
961 reLengthAbsolute( newLength );
962 mLabel->setText( i18n( "Length: %1 px", newLength ) );
965 QWidget::wheelEvent( e );
969 * draws the scale according to the orientation
971 void KLineal::drawScale( QPainter &painter )
973 painter.setPen( Qt::black );
974 QFont font = mScaleFont;
975 painter.setFont( font );
976 QFontMetrics metrics = painter.fontMetrics();
977 int longLen;
978 int shortStart;
979 int w = width();
980 int h = height();
982 // draw a frame around the whole thing
983 // (for some unknown reason, this doesn't show up anymore)
984 switch ( mOrientation ) {
985 case North:
986 default:
987 shortStart = 0;
988 longLen = w;
989 painter.drawLine( 0, 0, 0, h - 1 );
990 painter.drawLine( 0, h - 1, w - 1, h - 1 );
991 painter.drawLine( w - 1, h - 1, w - 1, 0 );
992 break;
994 case East:
995 shortStart = w;
996 longLen = h;
997 painter.drawLine( 0, 0, 0, h - 1 );
998 painter.drawLine( 0, h - 1, w - 1, h - 1 );
999 painter.drawLine( w - 1, 0, 0, 0 );
1000 break;
1002 case South:
1003 shortStart = h;
1004 longLen = w;
1005 painter.drawLine( 0, 0, 0, h - 1 );
1006 painter.drawLine( w - 1, h - 1, w - 1, 0 );
1007 painter.drawLine( w - 1, 0, 0, 0 );
1008 break;
1010 case West:
1011 shortStart = 0;
1012 longLen = h;
1013 painter.drawLine( 0, h - 1, w - 1, h - 1 );
1014 painter.drawLine( w - 1, h - 1, w - 1, 0 );
1015 painter.drawLine( w - 1, 0, 0, 0 );
1016 break;
1019 if ( !mRelativeScale ) {
1020 int digit;
1021 int len;
1022 for ( int x = 0; x < longLen; ++x ) {
1023 if ( mLeftToRight ) {
1024 digit = x + mOffset;
1025 } else {
1026 digit = longLen - x + mOffset;
1029 if ( digit % 2 ) continue;
1031 len = 6;
1033 if ( digit % 10 == 0 ) len = 10;
1034 if ( digit % 20 == 0 ) len = 15;
1035 if ( digit % 100 == 0 ) len = 18;
1037 if ( digit % 20 == 0 ) {
1038 font.setBold( digit % 100 == 0 );
1039 painter.setFont( font );
1040 QString units;
1041 units.sprintf( "%d", digit );
1042 QSize textSize = metrics.size( Qt::TextSingleLine, units );
1043 int tw = textSize.width();
1044 int th = textSize.height();
1046 switch ( mOrientation ) {
1047 case North:
1048 painter.drawText( x - tw / 2, shortStart + len + th, units );
1049 break;
1051 case South:
1052 painter.drawText( x - tw / 2, shortStart - len - 2, units );
1053 break;
1055 case East:
1056 painter.drawText( shortStart - len - tw - 2, x + th / 2 - 2, units );
1057 break;
1059 case West:
1060 painter.drawText( shortStart + len + 2, x + th / 2 - 2, units );
1061 break;
1065 switch( mOrientation ) {
1066 case North:
1067 painter.drawLine( x, shortStart, x, shortStart + len );
1068 break;
1069 case South:
1070 painter.drawLine( x, shortStart, x, shortStart - len );
1071 break;
1072 case East:
1073 painter.drawLine( shortStart, x, shortStart - len, x );
1074 break;
1075 case West:
1076 painter.drawLine( shortStart, x, shortStart + len, x );
1077 break;
1080 } else {
1081 float step = longLen / 100.f;
1082 int len;
1084 font.setBold( true );
1085 painter.setFont( font );
1087 for ( int i = 0; i <= 100; ++i ) {
1088 int x = (int)( i * step );
1089 len = ( i % 10 ) ? 6 : 15;
1091 if ( i % 10 == 0 ) {
1092 QString units;
1093 int value = mLeftToRight ? i : ( 100 - i );
1094 units.sprintf( "%d%%", value );
1095 QSize textSize = metrics.size( Qt::TextSingleLine, units );
1096 int tw = textSize.width();
1097 int th = textSize.height();
1099 switch ( mOrientation ) {
1100 case North:
1101 painter.drawText( x - tw / 2, shortStart + len + th, units );
1102 break;
1104 case South:
1105 painter.drawText( x - tw / 2, shortStart - len - 2, units );
1106 break;
1108 case East:
1109 painter.drawText( shortStart - len - tw - 2, x + th / 2 - 2, units );
1110 break;
1112 case West:
1113 painter.drawText( shortStart + len + 2, x + th / 2 - 2, units );
1114 break;
1118 switch( mOrientation ) {
1119 case North:
1120 painter.drawLine( x, shortStart, x, shortStart + len );
1121 break;
1122 case South:
1123 painter.drawLine( x, shortStart, x, shortStart - len );
1124 break;
1125 case East:
1126 painter.drawLine( shortStart, x, shortStart - len, x );
1127 break;
1128 case West:
1129 painter.drawLine( shortStart, x, shortStart + len, x );
1130 break;
1137 * actually draws the ruler
1139 void KLineal::paintEvent(QPaintEvent *inEvent )
1141 Q_UNUSED( inEvent );
1143 QPainter painter( this );
1144 drawBackground( painter );
1145 drawScale( painter );
1148 #include "klineal.moc"