compile
[kdegraphics.git] / kruler / klineal.cpp
blobf1792d42c96badd0512d2243012e5cdcba524f02
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 "krulersystemtray.h"
51 #include "qautosizelabel.h"
53 #include "ui_cfg_appearance.h"
54 #include "ui_cfg_advanced.h"
56 /**
57 * this is our cursor bitmap:
58 * a line 48 pixels long with an arrow pointing down
59 * and a sqare with a one pixel hole at the top (end)
61 static const uchar cursorBits[] = {
62 0x38, 0x28, 0x38, 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 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
67 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10,
70 /**
71 * create the thingy with no borders and set up
72 * its members
74 KLineal::KLineal( QWidget *parent )
75 : QWidget( parent ),
76 mDragging( false ),
77 mShortEdgeLen( 70 ),
78 mLenMenu( 0 ), // INFO This member could be eventually deleted
79 // since if mFullScreenAction is initialized
80 // mLenMenu should have been, too.
81 mFullScreenAction( 0 ),
82 mScaleDirectionAction( 0 ),
83 mCenterOriginAction( 0 ),
84 mOffsetAction( 0 ),
85 mClicked( false ),
86 mActionCollection( 0 ),
87 mCloseButton( 0 ),
88 mTrayIcon( 0 )
90 KWindowSystem::setType( winId(), NET::Override ); // or NET::Normal
91 KWindowSystem::setState( winId(), NET::KeepAbove );
93 setAttribute( Qt::WA_TranslucentBackground );
94 setWindowFlags( Qt::FramelessWindowHint );
96 setMinimumSize( 60, 60 );
97 setMaximumSize( 8000, 8000 );
98 setWhatsThis( i18n( "This is a tool to measure pixel distances and colors on the screen. "
99 "It is useful for working on layouts of dialogs, web pages etc." ) );
100 setMouseTracking( true );
102 QBitmap bim = QBitmap::fromData( QSize( 8, 48 ), cursorBits, QImage::Format_Mono );
103 QMatrix m;
104 m.rotate( 90.0 );
105 mNorthCursor = QCursor( bim, bim, 3, 47 );
106 bim = bim.transformed( m );
107 mEastCursor = QCursor( bim, bim, 0, 3 );
108 bim = bim.transformed( m );
109 mSouthCursor = QCursor( bim, bim, 4, 0 );
110 bim = bim.transformed( m );
111 mWestCursor = QCursor( bim, bim, 47, 4 );
113 mCurrentCursor = mNorthCursor;
114 mColor = RulerSettings::self()->bgColor();
115 mScaleFont = RulerSettings::self()->scaleFont();
116 mLongEdgeLen = RulerSettings::self()->length();
117 mOrientation = RulerSettings::self()->orientation();
118 mLeftToRight = RulerSettings::self()->leftToRight();
119 mOffset = RulerSettings::self()->offset();
120 mRelativeScale = RulerSettings::self()->relativeScale();
122 mLabel = new QAutoSizeLabel( this );
123 mLabel->setGeometry( 0, height() - 12, 32, 12 );
124 QFont labelFont( KGlobalSettings::generalFont().family(), 10 );
125 labelFont.setPixelSize( 10 );
126 mLabel->setFont( labelFont );
127 mLabel->setWhatsThis( i18n( "This is the current distance measured in pixels." ) );
128 mColorLabel = new QAutoSizeLabel( this );
129 mColorLabel->setAutoFillBackground( true );
130 QFont colorFont( KGlobalSettings::fixedFont().family(), 10 );
131 colorFont.setPixelSize( 10 );
132 mColorLabel->setFont( colorFont );
133 mColorLabel->move( mLabel->pos() + QPoint(0, 20) );
134 mColorLabel->setWhatsThis(i18n("This is the current color in hexadecimal rgb representation"
135 " as you may use it in HTML or as a QColor name. "
136 "The rectangles background shows the color of the pixel inside the "
137 "little square at the end of the line cursor." ) );
139 mBtnRotateLeft = new QToolButton( this );
140 mBtnRotateLeft->setIcon( KIcon( "object-rotate-left" ) );
141 mBtnRotateLeft->setToolTip( i18n( "Turn Left" ) );
142 connect( mBtnRotateLeft, SIGNAL( clicked() ), this, SLOT( turnLeft() ) );
144 mBtnRotateRight = new QToolButton( this );
145 mBtnRotateRight->setIcon( KIcon( "object-rotate-right" ) );
146 mBtnRotateRight->setToolTip( i18n( "Turn Right" ) );
147 connect( mBtnRotateRight, SIGNAL( clicked() ), this, SLOT( turnRight() ) );
149 resize( QSize( mLongEdgeLen, mShortEdgeLen ) );
151 //BEGIN setup menu and actions
152 mActionCollection = new KActionCollection( this );
153 mActionCollection->setConfigGroup( "Actions" );
155 mMenu = new KMenu( this );
156 mMenu->addTitle( i18n( "KRuler" ) );
157 KMenu *oriMenu = new KMenu( i18n( "&Orientation"), this );
158 addAction( oriMenu, KIcon( "kruler-north" ), i18nc( "Turn Kruler North", "&North" ),
159 this, SLOT( setNorth() ), Qt::Key_N, "turn_north" );
160 addAction( oriMenu, KIcon( "kruler-east" ), i18nc( "Turn Kruler East", "&East" ),
161 this, SLOT( setEast() ), Qt::Key_E, "turn_east" );
162 addAction( oriMenu, KIcon( "kruler-south" ), i18nc( "Turn Kruler South", "&South" ),
163 this, SLOT( setSouth() ), Qt::Key_S, "turn_south" );
164 addAction( oriMenu, KIcon( "kruler-west" ), i18nc( "Turn Kruler West", "&West" ),
165 this, SLOT( setWest() ), Qt::Key_W, "turn_west" );
166 addAction( oriMenu, KIcon( "object-rotate-right" ), i18n( "&Turn Right" ),
167 this, SLOT( turnRight() ), Qt::Key_R, "turn_right" );
168 addAction( oriMenu, KIcon( "object-rotate-left" ), i18n( "Turn &Left" ),
169 this, SLOT( turnLeft() ), Qt::Key_L, "turn_left" );
170 mMenu->addMenu( oriMenu );
172 mLenMenu = new KMenu( i18n( "&Length" ), this );
173 addAction( mLenMenu, KIcon(), i18nc( "Make Kruler Height Short", "&Short" ),
174 this, SLOT( setShortLength() ), Qt::CTRL + Qt::Key_S, "length_short" );
175 addAction( mLenMenu, KIcon(), i18nc( "Make Kruler Height Medium", "&Medium" ),
176 this, SLOT( setMediumLength() ), Qt::CTRL + Qt::Key_M, "length_medium" );
177 addAction( mLenMenu, KIcon(), i18nc( "Make Kruler Height Tall", "&Tall" ),
178 this, SLOT( setTallLength() ), Qt::CTRL + Qt::Key_T, "length_tall" );
179 addAction( mLenMenu, KIcon(), i18n("&Full Screen Width"),
180 this, SLOT( setFullLength() ), Qt::CTRL + Qt::Key_F, "length_full_length" );
181 mLenMenu->addSeparator();
182 addAction( mLenMenu, KIcon(), i18n( "Length..." ),
183 this, SLOT( slotLength() ), QKeySequence(), "set_length" );
184 mMenu->addMenu( mLenMenu );
186 KMenu* scaleMenu = new KMenu( i18n( "&Scale" ), this );
187 mScaleDirectionAction = addAction( scaleMenu, KIcon(), i18n( "Right To Left" ),
188 this, SLOT( switchDirection() ), Qt::Key_D, "right_to_left" );
189 mCenterOriginAction = addAction( scaleMenu, KIcon(), i18n( "Center origin" ),
190 this, SLOT( centerOrigin() ), Qt::Key_C, "center_origin" );
191 mCenterOriginAction->setEnabled( !mRelativeScale );
192 mOffsetAction = addAction( scaleMenu, KIcon(), i18n( "Offset..." ),
193 this, SLOT( slotOffset() ), Qt::Key_O, "set_offset" );
194 mOffsetAction->setEnabled( !mRelativeScale );
195 scaleMenu->addSeparator();
196 KAction *relativeScaleAction = addAction( scaleMenu, KIcon(), i18n( "Percentage" ),
197 0, 0, QKeySequence(), "toggle_percentage" );
198 relativeScaleAction->setCheckable( true );
199 relativeScaleAction->setChecked( mRelativeScale );
200 connect( relativeScaleAction, SIGNAL( toggled( bool ) ), this, SLOT( switchRelativeScale( bool ) ) );
201 mMenu->addMenu( scaleMenu );
203 mOpacity = RulerSettings::self()->opacity();
204 KMenu* opacityMenu = new KMenu( i18n( "O&pacity" ), this );
205 QWidgetAction *opacityAction = new QWidgetAction( this );
206 QSlider *slider = new QSlider( this );
207 slider->setMinimum( 0 );
208 slider->setMaximum( 255 );
209 slider->setSingleStep( 1 );
210 slider->setOrientation( Qt::Horizontal );
211 slider->setValue( RulerSettings::self()->opacity() );
212 connect( slider, SIGNAL( valueChanged( int ) ), this, SLOT( slotOpacity( int ) ) );
213 opacityAction->setDefaultWidget( slider );
214 opacityMenu->addAction( opacityAction );
215 mMenu->addMenu( opacityMenu );
217 KAction *keyBindings = KStandardAction::keyBindings( this, SLOT( slotKeyBindings() ), this );
218 mActionCollection->addAction( "key_bindings", keyBindings );
219 mMenu->addAction( keyBindings );
220 KAction *preferences = KStandardAction::preferences( this, SLOT( slotPreferences() ), this );
221 mActionCollection->addAction( "preferences", preferences );
222 mMenu->addAction( preferences );
223 mMenu->addSeparator();
224 KAction *copyColorAction = KStandardAction::copy( this, SLOT( copyColor() ), this );
225 copyColorAction->setText( i18n( "Copy Color" ) );
226 mActionCollection->addAction( "copy_color", copyColorAction );
227 mMenu->addAction( copyColorAction );
228 mMenu->addSeparator();
229 mMenu->addMenu( ( new KHelpMenu( this, KGlobal::mainComponent().aboutData(), true ) )->menu() );
230 mMenu->addSeparator();
231 if ( RulerSettings::self()->trayIcon() ) {
232 createSystemTray();
235 KAction *quit = KStandardAction::quit( kapp, SLOT( quit() ), this );
236 mActionCollection->addAction( "quit", quit );
237 mMenu->addAction( quit );
239 mActionCollection->associateWidget( this );
240 mActionCollection->readSettings();
242 mLastClickPos = geometry().topLeft() + QPoint( width() / 2, height() / 2 );
244 hideLabel();
245 setOrientation( mOrientation );
249 KLineal::~KLineal()
253 void KLineal::createSystemTray()
255 KAction *closeAction = KStandardAction::close( this, SLOT( slotClose() ), this );
256 mActionCollection->addAction( "close", closeAction );
257 mMenu->addAction( closeAction );
259 mCloseButton = new QToolButton( this );
260 mCloseButton->setIcon( closeAction->icon() );
261 mCloseButton->setToolTip( closeAction->text().remove( '&' ) );
262 connect( mCloseButton, SIGNAL( clicked() ), this, SLOT( slotClose() ) );
263 mTrayIcon = new KRulerSystemTray( KIcon( "kruler" ), this,mActionCollection );
264 mTrayIcon->show();
268 KAction* KLineal::addAction( KMenu *menu, KIcon icon, const QString& text,
269 const QObject* receiver, const char* member,
270 const QKeySequence &shortcut, const QString& name )
272 KAction *action = new KAction( icon, text, mActionCollection );
273 action->setShortcut( shortcut );
274 if ( receiver ) {
275 connect( action, SIGNAL( triggered() ), receiver, member );
277 menu->addAction( action );
278 mActionCollection->addAction( name, action );
279 return action;
282 void KLineal::slotClose()
284 hide();
287 void KLineal::slotQuit()
289 kapp->quit();
292 void KLineal::move( int x, int y )
294 move( QPoint( x, y ) );
297 void KLineal::move(const QPoint &p)
299 setGeometry( QRect( p, size() ) );
302 QPoint KLineal::pos() const
304 return frameGeometry().topLeft();
307 int KLineal::x() const
309 return pos().x();
312 int KLineal::y() const
314 return pos().y();
317 void KLineal::drawBackground( QPainter& painter )
319 QColor a, b, bg = mColor;
320 QLinearGradient gradient;
321 switch ( mOrientation ) {
322 case North:
323 a = bg.light( 120 );
324 b = bg.dark( 130 );
325 gradient = QLinearGradient( 1, 0, 1, height() );
326 break;
328 case South:
329 b = bg.light( 120 );
330 a = bg.dark( 130 );
331 gradient = QLinearGradient( 1, 0, 1, height() );
332 break;
334 case West:
335 a = bg.light( 120 );
336 b = bg.dark( 130 );
337 gradient = QLinearGradient( 0, 1, width(), 1 );
338 break;
340 case East:
341 b = bg.light( 120 );
342 a = bg.dark( 130 );
343 gradient = QLinearGradient( 0, 1, width(), 1 );
344 break;
346 a.setAlpha( mOpacity );
347 b.setAlpha( mOpacity );
348 gradient.setColorAt( 0, a );
349 gradient.setColorAt( 1, b );
350 painter.fillRect( rect(), QBrush( gradient ) );
353 void KLineal::setOrientation( int inOrientation )
355 QRect r = frameGeometry();
356 int nineties = (int)inOrientation - (int)mOrientation;
357 mOrientation = ( inOrientation + 4 ) % 4;
358 QPoint center = mLastClickPos, newTopLeft;
360 if ( mClicked ) {
361 center = mLastClickPos;
362 mClicked = false;
363 } else {
364 center = r.topLeft() + QPoint( width() / 2, height() / 2 );
367 if ( nineties % 2 ) {
368 newTopLeft = QPoint( center.x() - height() / 2, center.y() - width() / 2 );
369 } else {
370 newTopLeft = r.topLeft();
373 if ( mOrientation == North || mOrientation == South ) {
374 r.setSize( QSize( mLongEdgeLen, mShortEdgeLen ) );
375 } else {
376 r.setSize( QSize( mShortEdgeLen, mLongEdgeLen ) );
379 r.moveTo(newTopLeft);
381 QRect desktop = KGlobalSettings::desktopGeometry( this );
383 if ( r.top() < desktop.top() ) {
384 r.moveTop( desktop.top() );
387 if ( r.bottom() > desktop.bottom() ) {
388 r.moveBottom( desktop.bottom() );
391 if ( r.left() < desktop.left() ) {
392 r.moveLeft( desktop.left() );
395 if ( r.right() > desktop.right() ) {
396 r.moveRight( desktop.right() );
399 setGeometry( r );
400 switch( mOrientation ) {
401 case North:
402 mLabel->move( 4, height()-mLabel->height() - 4 );
403 mColorLabel->move( mLabel->pos() + QPoint( 0, -20 ) );
404 mCurrentCursor = mNorthCursor;
405 break;
407 case South:
408 mLabel->move( 4, 4 );
409 mColorLabel->move( mLabel->pos() + QPoint( 0, 20 ) );
410 mCurrentCursor = mSouthCursor;
411 break;
413 case East:
414 mLabel->move( 4, 4 );
415 mColorLabel->move( mLabel->pos() + QPoint( 0, 20 ) );
416 mCurrentCursor = mEastCursor;
417 break;
419 case West:
420 mLabel->move( width()-mLabel->width() - 4, 4 );
421 mColorLabel->move( mLabel->pos() + QPoint( -5, 20 ) );
422 mCurrentCursor = mWestCursor;
423 break;
426 adjustButtons();
428 if ( mLenMenu && mFullScreenAction ) {
429 mFullScreenAction->setText( mOrientation % 2 ? i18n( "&Full Screen Height" ) : i18n( "&Full Screen Width" ) );
432 updateScaleDirectionMenuItem();
434 setCursor( mCurrentCursor );
435 repaint();
436 saveSettings();
439 void KLineal::setNorth()
441 setOrientation( North );
444 void KLineal::setEast()
446 setOrientation( East );
449 void KLineal::setSouth()
451 setOrientation( South );
454 void KLineal::setWest()
456 setOrientation( West );
459 void KLineal::turnRight()
461 setOrientation( mOrientation - 1 );
464 void KLineal::turnLeft()
466 setOrientation( mOrientation + 1 );
469 void KLineal::reLength( int percentOfScreen )
471 if ( percentOfScreen < 10 ) {
472 return;
475 QRect r = KGlobalSettings::desktopGeometry( this );
477 if ( mOrientation == North || mOrientation == South ) {
478 mLongEdgeLen = r.width() * percentOfScreen / 100;
479 resize( mLongEdgeLen, height() );
480 } else {
481 mLongEdgeLen = r.height() * percentOfScreen / 100;
482 resize( width(), mLongEdgeLen );
485 if ( x() + width() < 10 ) {
486 move( 10, y() );
489 if ( y() + height() < 10 ) {
490 move( x(), 10 );
493 adjustButtons();
494 saveSettings();
497 void KLineal::reLengthAbsolute( int length )
499 if ( length < 100 ) {
500 return;
503 QRect r = KGlobalSettings::desktopGeometry( this );
505 mLongEdgeLen = length;
506 if ( mOrientation == North || mOrientation == South ) {
507 resize( mLongEdgeLen, height() );
508 } else {
509 resize( width(), mLongEdgeLen );
512 if ( x() + width() < 10 ) {
513 move( 10, y() );
516 if ( y() + height() < 10 ) {
517 move( x(), 10 );
520 adjustButtons();
521 saveSettings();
524 void KLineal::updateScaleDirectionMenuItem()
526 if ( !mScaleDirectionAction ) return;
528 QString label;
530 if ( mOrientation == North || mOrientation == South ) {
531 label = mLeftToRight ? i18n( "Right To Left" ) : i18n( "Left To Right" );
532 } else {
533 label = mLeftToRight ? i18n( "Bottom To Top" ) : i18n( "Top To Bottom" );
536 mScaleDirectionAction->setText( label );
539 void KLineal::setShortLength()
541 reLength( 30 );
544 void KLineal::setMediumLength()
546 reLength( 50 );
549 void KLineal::setTallLength()
551 reLength( 75 );
554 void KLineal::setFullLength()
556 reLength( 100 );
559 void KLineal::switchDirection()
561 mLeftToRight = !mLeftToRight;
562 updateScaleDirectionMenuItem();
563 repaint();
564 adjustLabel();
565 saveSettings();
568 void KLineal::centerOrigin()
570 mOffset = -( mLongEdgeLen / 2 );
571 repaint();
572 adjustLabel();
573 saveSettings();
576 void KLineal::slotOffset()
578 bool ok;
579 int newOffset = KInputDialog::getInteger( i18n( "Scale offset" ),
580 i18n( "Offset:" ), mOffset,
581 -2147483647, 2147483647, 1, &ok, this );
583 if ( ok ) {
584 mOffset = newOffset;
585 repaint();
586 adjustLabel();
587 saveSettings();
591 void KLineal::slotLength()
593 bool ok;
594 QRect r = KGlobalSettings::desktopGeometry( this );
595 int width = ( ( mOrientation == North ) || ( mOrientation == South ) ) ? r.width() : r.height();
596 int newLength = KInputDialog::getInteger( i18n( "Ruler Length" ),
597 i18n( "Length:" ), mLongEdgeLen,
598 0, width, 1, &ok, this );
600 if ( ok ) {
601 reLengthAbsolute( newLength );
605 void KLineal::slotOpacity( int value )
607 mOpacity = value;
608 repaint();
609 RulerSettings::self()->setOpacity( value );
610 RulerSettings::self()->writeConfig();
613 void KLineal::slotKeyBindings()
615 KShortcutsDialog::configure( mActionCollection );
618 void KLineal::slotPreferences()
620 KConfigDialog *dialog = new KConfigDialog( this, "settings", RulerSettings::self() );
622 Ui::ConfigAppearance appearanceConfig;
623 QWidget *appearanceConfigWidget = new QWidget( dialog );
624 appearanceConfig.setupUi( appearanceConfigWidget );
625 appearanceConfig.kcfg_CloseButtonVisible->setEnabled( appearanceConfig.kcfg_TrayIcon->isChecked() );
626 dialog->addPage( appearanceConfigWidget, i18n( "Appearance" ), "preferences-desktop-default-applications" );
628 Ui::ConfigAdvanced advancedConfig;
629 QWidget *advancedConfigWidget = new QWidget( dialog );
630 advancedConfig.setupUi( advancedConfigWidget );
631 dialog->addPage( advancedConfigWidget, i18n( "Advanced" ), "preferences-other" );
633 connect(dialog, SIGNAL(settingsChanged(const QString&)), SLOT(loadConfig()));
634 dialog->exec();
635 delete dialog;
638 void KLineal::loadConfig()
640 mColor = RulerSettings::self()->bgColor();
641 mScaleFont = RulerSettings::self()->scaleFont();
642 saveSettings();
644 if ( RulerSettings::self()->trayIcon() ) {
645 if ( !mTrayIcon ) {
646 createSystemTray();
647 //need to adjust button
648 adjustButtons();
650 else
651 mTrayIcon->show();
653 else {
654 if ( mTrayIcon ) {
655 mTrayIcon->hide();
658 repaint();
662 void KLineal::switchRelativeScale( bool checked )
664 mRelativeScale = checked;
666 mCenterOriginAction->setEnabled( !mRelativeScale );
667 mOffsetAction->setEnabled( !mRelativeScale );
669 repaint();
670 adjustLabel();
671 saveSettings();
675 * save the ruler color to the config file
677 void KLineal::saveSettings()
679 RulerSettings::self()->setBgColor( mColor );
680 RulerSettings::self()->setScaleFont( mScaleFont );
681 RulerSettings::self()->setLength( mLongEdgeLen );
682 RulerSettings::self()->setOrientation( mOrientation );
683 RulerSettings::self()->setLeftToRight( mLeftToRight );
684 RulerSettings::self()->setOffset( mOffset );
685 RulerSettings::self()->setRelativeScale( mRelativeScale );
686 RulerSettings::self()->writeConfig();
689 void KLineal::copyColor()
691 QApplication::clipboard()->setText( mColorLabel->text() );
695 * lets the context menu appear at current cursor position
697 void KLineal::showMenu()
699 QPoint pos = QCursor::pos();
700 mMenu->popup( pos );
704 * overwritten to switch the value label and line cursor on
706 void KLineal::enterEvent( QEvent *inEvent )
708 Q_UNUSED( inEvent );
710 if ( !mDragging ) {
711 showLabel();
716 * overwritten to switch the value label and line cursor off
718 void KLineal::leaveEvent( QEvent *inEvent )
720 Q_UNUSED( inEvent );
722 if ( !geometry().contains( QCursor::pos() ) ) {
723 hideLabel();
728 * shows the value lable
730 void KLineal::showLabel()
732 adjustLabel();
733 mLabel->show();
734 mColorLabel->show();
735 if ( RulerSettings::self()->rotateButtonsVisible() ) {
736 mBtnRotateLeft->show();
737 mBtnRotateRight->show();
739 if ( mCloseButton &&
740 RulerSettings::self()->closeButtonVisible() &&
741 RulerSettings::self()->trayIcon()) {
742 mCloseButton->show();
747 * hides the value label
749 void KLineal::hideLabel()
751 mLabel->hide();
752 mColorLabel->hide();
753 mBtnRotateLeft->hide();
754 mBtnRotateRight->hide();
755 if ( mCloseButton ) {
756 mCloseButton->hide();
761 * updates the current value label
763 void KLineal::adjustLabel()
765 QString s;
766 QPoint cpos = QCursor::pos();
768 int digit = ( mOrientation == North || mOrientation == South ) ? cpos.x() - x() : cpos.y() - y();
770 if ( !mRelativeScale ) {
771 if ( mLeftToRight ) {
772 digit += mOffset;
773 } else {
774 digit = mLongEdgeLen - digit + mOffset;
776 } else {
777 // INFO: Perhaps use float also for displaying relative value
778 digit = (int)( ( digit * 100.f ) / mLongEdgeLen );
780 if ( !mLeftToRight ) {
781 digit = 100 - digit;
785 s.sprintf( "%d%s", digit, ( mRelativeScale ? "%" : " px" ) );
786 mLabel->setText( s );
790 * Updates the position of the tool buttons
792 void KLineal::adjustButtons()
794 switch( mOrientation ) {
795 case North:
796 mBtnRotateLeft->move( mLongEdgeLen / 2 - 28, height() - 31 );
797 mBtnRotateRight->move( mLongEdgeLen / 2 + 2, height() - 31 );
798 if ( mCloseButton ) {
799 mCloseButton->move( width() - 31, height() - 31 );
801 break;
803 case South:
804 mBtnRotateLeft->move( mLongEdgeLen / 2 - 28, 5 );
805 mBtnRotateRight->move( mLongEdgeLen / 2 + 2, 5 );
806 if ( mCloseButton ) {
807 mCloseButton->move( width() - 31, 5 );
809 break;
811 case East:
812 mBtnRotateLeft->move( 5, mLongEdgeLen / 2 - 28 );
813 mBtnRotateRight->move( 5, mLongEdgeLen / 2 + 2 );
814 if ( mCloseButton ) {
815 mCloseButton->move( 5, height() - 31 );
817 break;
819 case West:
820 mBtnRotateLeft->move( width() - 31, mLongEdgeLen / 2 - 28 );
821 mBtnRotateRight->move( width() - 31, mLongEdgeLen / 2 + 2 );
822 if ( mCloseButton ) {
823 mCloseButton->move( width() - 31, height() - 31 );
825 break;
829 void KLineal::keyPressEvent( QKeyEvent *e )
831 QPoint dist;
833 switch ( e->key() ) {
834 case Qt::Key_F1:
835 KToolInvocation::invokeHelp();
836 return;
838 case Qt::Key_Left:
839 dist.setX( -1 );
840 break;
842 case Qt::Key_Right:
843 dist.setX( 1 );
844 break;
846 case Qt::Key_Up:
847 dist.setY( -1 );
848 break;
850 case Qt::Key_Down:
851 dist.setY( 1 );
852 break;
854 default:
855 QWidget::keyPressEvent(e);
856 return;
859 if ( e->modifiers() & Qt::ShiftModifier ) {
860 dist *= 10;
863 move( pos() + dist );
864 KNotification::event( 0, "cursormove", QString() );
868 * overwritten to handle the line cursor which is a separate widget outside the main
869 * window. Also used for dragging.
871 void KLineal::mouseMoveEvent( QMouseEvent *inEvent )
873 Q_UNUSED( inEvent );
875 if ( mDragging && this == mouseGrabber() && !RulerSettings::self()->nativeMoving() ) {
876 move( QCursor::pos() - mDragOffset );
877 } else {
878 QPoint p = QCursor::pos();
880 switch (mOrientation) {
881 case North:
882 p.setY( p.y() - 46 );
883 break;
885 case East:
886 p.setX( p.x() + 46 );
887 break;
889 case West:
890 p.setX( p.x() - 46 );
891 break;
893 case South:
894 p.setY( p.y() + 46 );
895 break;
898 QColor color = KColorDialog::grabColor( p );
899 int h, s, v;
900 color.getHsv( &h, &s, &v );
901 mColorLabel->setText( color.name().toUpper() );
902 QPalette palette = mColorLabel->palette();
903 palette.setColor( mColorLabel->backgroundRole(), color );
904 if ( v < 255 / 2 ) {
905 v = 255;
906 } else {
907 v = 0;
909 color.setHsv( h, s, v );
910 palette.setColor( mColorLabel->foregroundRole(), color );
911 mColorLabel->setPalette( palette );
912 adjustLabel();
917 * overwritten for dragging and context menu
919 void KLineal::mousePressEvent( QMouseEvent *inEvent )
921 mLastClickPos = QCursor::pos();
922 hideLabel();
924 QRect gr = geometry();
925 mDragOffset = mLastClickPos - QPoint( gr.left(), gr.top() );
926 if ( inEvent->button() == Qt::LeftButton ) {
927 #ifdef Q_WS_X11
928 if ( RulerSettings::self()->nativeMoving() ) {
929 XUngrabPointer( QX11Info::display(), QX11Info::appTime() );
930 NETRootInfo wm_root( QX11Info::display(), NET::WMMoveResize );
931 wm_root.moveResizeRequest( winId(), inEvent->globalX(), inEvent->globalY(), NET::Move );
932 } else {
933 #endif
934 if ( !mDragging ) {
935 grabMouse( Qt::SizeAllCursor );
936 mDragging = true;
938 #ifdef Q_WS_X11
940 #endif
941 } else if ( inEvent->button() == Qt::MidButton ) {
942 mClicked = true;
943 turnLeft();
944 } else if ( inEvent->button() == Qt::RightButton ) {
945 showMenu();
950 * overwritten for dragging
952 void KLineal::mouseReleaseEvent( QMouseEvent *inEvent )
954 Q_UNUSED( inEvent );
956 #ifdef Q_WS_X11
957 if ( RulerSettings::self()->nativeMoving() ) {
958 NETRootInfo wm_root( QX11Info::display(), NET::WMMoveResize );
959 wm_root.moveResizeRequest( winId(), inEvent->globalX(), inEvent->globalY(), NET::MoveResizeCancel );
960 } else {
961 #endif
962 if ( mDragging ) {
963 mDragging = false;
964 releaseMouse();
966 #ifdef Q_WS_X11
968 #endif
970 showLabel();
973 void KLineal::wheelEvent( QWheelEvent *e )
975 int numDegrees = e->delta() / 8;
976 int numSteps = numDegrees / 15;
978 // changing offset
979 if ( e->buttons() == Qt::LeftButton ) {
980 if ( !mRelativeScale ) {
981 mLabel->show();
982 mOffset += numSteps;
984 repaint();
985 mLabel->setText( i18n( "Offset: %1", mOffset ) );
986 saveSettings();
988 } else { // changing length
989 int newLength = mLongEdgeLen + numSteps;
990 reLengthAbsolute( newLength );
991 mLabel->setText( i18n( "Length: %1 px", newLength ) );
994 QWidget::wheelEvent( e );
998 * draws the scale according to the orientation
1000 void KLineal::drawScale( QPainter &painter )
1002 painter.setPen( Qt::black );
1003 QFont font = mScaleFont;
1004 painter.setFont( font );
1005 QFontMetrics metrics = painter.fontMetrics();
1006 int longLen;
1007 int shortStart;
1008 int w = width();
1009 int h = height();
1011 // draw a frame around the whole thing
1012 // (for some unknown reason, this doesn't show up anymore)
1013 switch ( mOrientation ) {
1014 case North:
1015 default:
1016 shortStart = 0;
1017 longLen = w;
1018 painter.drawLine( 0, 0, 0, h - 1 );
1019 painter.drawLine( 0, h - 1, w - 1, h - 1 );
1020 painter.drawLine( w - 1, h - 1, w - 1, 0 );
1021 break;
1023 case East:
1024 shortStart = w;
1025 longLen = h;
1026 painter.drawLine( 0, 0, 0, h - 1 );
1027 painter.drawLine( 0, h - 1, w - 1, h - 1 );
1028 painter.drawLine( w - 1, 0, 0, 0 );
1029 break;
1031 case South:
1032 shortStart = h;
1033 longLen = w;
1034 painter.drawLine( 0, 0, 0, h - 1 );
1035 painter.drawLine( w - 1, h - 1, w - 1, 0 );
1036 painter.drawLine( w - 1, 0, 0, 0 );
1037 break;
1039 case West:
1040 shortStart = 0;
1041 longLen = h;
1042 painter.drawLine( 0, h - 1, w - 1, h - 1 );
1043 painter.drawLine( w - 1, h - 1, w - 1, 0 );
1044 painter.drawLine( w - 1, 0, 0, 0 );
1045 break;
1048 if ( !mRelativeScale ) {
1049 int digit;
1050 int len;
1051 for ( int x = 0; x < longLen; ++x ) {
1052 if ( mLeftToRight ) {
1053 digit = x + mOffset;
1054 } else {
1055 digit = longLen - x + mOffset;
1058 if ( digit % 2 ) continue;
1060 len = 6;
1062 if ( digit % 10 == 0 ) len = 10;
1063 if ( digit % 20 == 0 ) len = 15;
1064 if ( digit % 100 == 0 ) len = 18;
1066 if ( digit % 20 == 0 ) {
1067 font.setBold( digit % 100 == 0 );
1068 painter.setFont( font );
1069 QString units;
1070 units.sprintf( "%d", digit );
1071 QSize textSize = metrics.size( Qt::TextSingleLine, units );
1072 int tw = textSize.width();
1073 int th = textSize.height();
1075 switch ( mOrientation ) {
1076 case North:
1077 painter.drawText( x - tw / 2, shortStart + len + th, units );
1078 break;
1080 case South:
1081 painter.drawText( x - tw / 2, shortStart - len - 2, units );
1082 break;
1084 case East:
1085 painter.drawText( shortStart - len - tw - 2, x + th / 2 - 2, units );
1086 break;
1088 case West:
1089 painter.drawText( shortStart + len + 2, x + th / 2 - 2, units );
1090 break;
1094 switch( mOrientation ) {
1095 case North:
1096 painter.drawLine( x, shortStart, x, shortStart + len );
1097 break;
1098 case South:
1099 painter.drawLine( x, shortStart, x, shortStart - len );
1100 break;
1101 case East:
1102 painter.drawLine( shortStart, x, shortStart - len, x );
1103 break;
1104 case West:
1105 painter.drawLine( shortStart, x, shortStart + len, x );
1106 break;
1109 } else {
1110 float step = longLen / 100.f;
1111 int len;
1113 font.setBold( true );
1114 painter.setFont( font );
1116 for ( int i = 0; i <= 100; ++i ) {
1117 int x = (int)( i * step );
1118 len = ( i % 10 ) ? 6 : 15;
1120 if ( i % 10 == 0 ) {
1121 QString units;
1122 int value = mLeftToRight ? i : ( 100 - i );
1123 units.sprintf( "%d%%", value );
1124 QSize textSize = metrics.size( Qt::TextSingleLine, units );
1125 int tw = textSize.width();
1126 int th = textSize.height();
1128 switch ( mOrientation ) {
1129 case North:
1130 painter.drawText( x - tw / 2, shortStart + len + th, units );
1131 break;
1133 case South:
1134 painter.drawText( x - tw / 2, shortStart - len - 2, units );
1135 break;
1137 case East:
1138 painter.drawText( shortStart - len - tw - 2, x + th / 2 - 2, units );
1139 break;
1141 case West:
1142 painter.drawText( shortStart + len + 2, x + th / 2 - 2, units );
1143 break;
1147 switch( mOrientation ) {
1148 case North:
1149 painter.drawLine( x, shortStart, x, shortStart + len );
1150 break;
1151 case South:
1152 painter.drawLine( x, shortStart, x, shortStart - len );
1153 break;
1154 case East:
1155 painter.drawLine( shortStart, x, shortStart - len, x );
1156 break;
1157 case West:
1158 painter.drawLine( shortStart, x, shortStart + len, x );
1159 break;
1166 * actually draws the ruler
1168 void KLineal::paintEvent(QPaintEvent *inEvent )
1170 Q_UNUSED( inEvent );
1172 QPainter painter( this );
1173 drawBackground( painter );
1174 drawScale( painter );
1177 #include "klineal.moc"