1 /***************************************************************************
2 klineal.cpp - description
4 Begin : Fri Oct 13 2000
5 Copyright : 2000 by Till Krech
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
23 #include <QMouseEvent>
29 #include <kglobalsettings.h>
30 #include <kiconloader.h>
31 #include <khelpmenu.h>
33 #include <knotification.h>
34 #include <kwindowsystem.h>
35 #include <KStandardGuiItem>
36 #include <ktoolinvocation.h>
37 #include <kfontdialog.h>
40 #include <kapplication.h>
42 #define CFG_KEY_BGCOLOR "BgColor"
43 #define CFG_KEY_SCALE_FONT "ScaleFont"
44 #define CFG_KEY_LENGTH "Length"
45 #define CFG_GROUP_SETTINGS "StoredSettings"
46 #define DEFAULT_RULER_COLOR QColor(255, 200, 80)
47 #define FULLSCREENID 23
50 * this is our cursor bitmap:
51 * a line 48 pixels long with an arrow pointing down
52 * and a sqare with a one pixel hole at the top (end)
54 static const uchar cursorBits
[] = {
55 0x38, 0x28, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10,
56 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
57 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
58 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
59 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
60 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10,
64 * create the thingy with no borders and set up
67 KLineal::KLineal(QWidget
*parent
):QWidget(parent
),mColorSelector(this){
69 KWindowSystem::setType(winId(), NET::Override
); // or NET::Normal
70 KWindowSystem::setState(winId(), NET::KeepAbove
);
72 i18n("This is a tool to measure pixel distances and colors on the screen. "
73 "It is useful for working on layouts of dialogs, web pages etc."));
74 QBitmap bim
= QBitmap::fromData(QSize(8, 48), cursorBits
, QImage::Format_Mono
);
77 mNorthCursor
= QCursor(bim
, bim
, 3, 47);
78 bim
= bim
.transformed(m
);
79 mEastCursor
= QCursor(bim
, bim
, 0, 3);
80 bim
= bim
.transformed(m
);
81 mSouthCursor
= QCursor(bim
, bim
, 4, 0);
82 bim
= bim
.transformed(m
);
83 mWestCursor
= QCursor(bim
, bim
, 47, 4);
85 mCurrentCursor
= mNorthCursor
;
86 setMinimumSize(60,60);
87 setMaximumSize(8000,8000);
88 KSharedConfig::Ptr cfg
= KGlobal::config();
89 QColor defaultColor
= DEFAULT_RULER_COLOR
;
90 QFont
defaultFont(KGlobalSettings::generalFont().family(), 8);
91 defaultFont
.setPixelSize(8);
93 KConfigGroup
cfgcg(cfg
, CFG_GROUP_SETTINGS
);
94 mColor
= cfgcg
.readEntry(CFG_KEY_BGCOLOR
, defaultColor
);
95 mScaleFont
= cfgcg
.readEntry(CFG_KEY_SCALE_FONT
, defaultFont
);
96 mLongEdgeLen
= cfgcg
.readEntry(CFG_KEY_LENGTH
, 600);
98 mColor
= defaultColor
;
99 mScaleFont
= defaultFont
;
102 kDebug() << "mLongEdgeLen=" << mLongEdgeLen
;
105 mLabel
= new QLabel(this);
106 mLabel
->setGeometry(0,height()-12,32,12);
107 QFont
labelFont(KGlobalSettings::generalFont().family(), 10);
108 labelFont
.setPixelSize(10);
109 mLabel
->setFont(labelFont
);
110 mLabel
->setWhatsThis(i18n("This is the current distance measured in pixels."));
111 mColorLabel
= new QLabel(this);
112 mColorLabel
->setAutoFillBackground(true);
113 mColorLabel
->resize(45,12);
115 QFont
colorFont(KGlobalSettings::fixedFont().family(), 10);
116 colorFont
.setPixelSize(10);
117 mColorLabel
->setFont(colorFont
);
118 mColorLabel
->move(mLabel
->pos() + QPoint(0, 20));
119 mColorLabel
->setWhatsThis(i18n(
120 "This is the current color in hexadecimal rgb representation as you may use it in HTML or as a QColor name. "
121 "The rectangles background shows the color of the pixel inside the "
122 "little square at the end of the line cursor."));
124 resize(QSize(mLongEdgeLen
, mShortEdgeLen
));
125 setMouseTracking(true);
127 mOrientation
= South
;
129 setOrientation(South
);
130 // setMediumLength();
131 mMenu
= new KMenu(this);
132 mMenu
->addTitle(i18n("KRuler"));
133 KMenu
*oriMenu
= new KMenu(this);
134 oriMenu
->addAction(KIcon("kruler-north"), i18nc("Turn Kruler North", "&North"), this, SLOT(setNorth()), Qt::Key_N
);
135 oriMenu
->addAction(KIcon("kruler-east"), i18nc("Turn Kruler East", "&East"), this, SLOT(setEast()), Qt::Key_E
);
136 oriMenu
->addAction(KIcon("kruler-south"), i18nc("Turn Kruler South", "&South"), this, SLOT(setSouth()), Qt::Key_S
);
137 oriMenu
->addAction(KIcon("kruler-west"), i18nc("Turn Kruler West", "&West"), this, SLOT(setWest()), Qt::Key_W
);
138 oriMenu
->addAction(KIcon("object-rotate-right"), i18n("&Turn Right"), this, SLOT(turnRight()), Qt::Key_R
);
139 oriMenu
->addAction(KIcon("object-rotate-left"), i18n("Turn &Left"), this, SLOT(turnLeft()), Qt::Key_L
);
140 new QShortcut( Qt::Key_N
, this, SLOT(setNorth()));
141 new QShortcut(Qt::Key_E
,this,SLOT(setEast()));
142 new QShortcut(Qt::Key_S
,this, SLOT(setSouth()));
143 new QShortcut(Qt::Key_W
,this, SLOT(setWest()));
144 new QShortcut(Qt::Key_R
,this, SLOT(turnRight()));
145 new QShortcut(Qt::Key_L
,this, SLOT(turnLeft()));
146 oriMenu
->setTitle(i18n("&Orientation"));
147 mMenu
->addMenu(oriMenu
);
148 mLenMenu
= new KMenu(this);
149 mLenMenu
->addAction(i18nc("Make Kruler Height Short", "&Short"), this, SLOT(setShortLength()), Qt::CTRL
+Qt::Key_S
);
150 mLenMenu
->addAction(i18nc("Make Kruler Height Medium", "&Medium"), this, SLOT(setMediumLength()), Qt::CTRL
+Qt::Key_M
);
151 mLenMenu
->addAction(i18nc("Make Kruler Height Tall", "&Tall"), this, SLOT(setTallLength()), Qt::CTRL
+Qt::Key_T
);
152 mFullScreenAction
= mLenMenu
->addAction(i18n("&Full Screen Width"), this, SLOT(setFullLength()), Qt::CTRL
+Qt::Key_F
);
153 new QShortcut(Qt::CTRL
+Qt::Key_S
,this, SLOT(setShortLength()));
154 new QShortcut(Qt::CTRL
+Qt::Key_M
,this, SLOT(setMediumLength()));
155 new QShortcut(Qt::CTRL
+Qt::Key_T
,this, SLOT(setTallLength()));
156 new QShortcut(Qt::CTRL
+Qt::Key_F
,this, SLOT(setFullLength()));
157 mLenMenu
->setTitle(i18n("&Length"));
158 mMenu
->addMenu(mLenMenu
);
159 mMenu
->addAction(KIcon("preferences-desktop-color"), i18n("&Choose Color..."), this, SLOT(choseColor()), Qt::CTRL
+Qt::Key_C
);
160 mMenu
->addAction(KIcon("preferences-desktop-font"), i18n("Choose &Font..."), this, SLOT(choseFont()), Qt::Key_F
);
161 new QShortcut(Qt::CTRL
+Qt::Key_C
,this, SLOT(choseColor()));
162 new QShortcut(Qt::Key_F
,this, SLOT(choseFont()));
163 mMenu
->addSeparator();
164 mMenu
->addMenu((new KHelpMenu(this, KGlobal::mainComponent().aboutData(), true))->menu());
165 mMenu
->addSeparator();
166 mMenu
->addAction(KIcon("application-exit"), KStandardGuiItem::quit().text(), kapp
, SLOT(quit()), Qt::CTRL
+Qt::Key_Q
);
167 new QShortcut(Qt::CTRL
+Qt::Key_Q
,this, SLOT(slotQuit()));
168 mLastClickPos
= geometry().topLeft()+QPoint(width()/2, height()/2);
174 void KLineal::slotQuit()
179 void KLineal::move(int x
, int y
) {
183 void KLineal::move(const QPoint
&p
) {
184 setGeometry(QRect(p
, size()));
187 QPoint
KLineal::pos() {
188 QRect r
= frameGeometry();
198 static void rotateRect(QRect
&r
, const QPoint
¢er
, int nineties
) {
199 static int sintab
[4] = {0,1,0,-1};
200 static int costab
[4] = {1,0,-1,0};
204 nineties
= -nineties
+4;
207 r
.translate(-center
.x(), -center
.y());
208 r
.getCoords(&x1
, &y1
, &x2
, &y2
);
210 x1
* costab
[i
] + y1
* sintab
[i
],
211 -x1
* sintab
[i
] + y1
* costab
[i
],
212 x2
* costab
[i
] + y2
* sintab
[i
],
213 -x2
* sintab
[i
] + y2
* costab
[i
]);
215 r
.translate(center
.x(), center
.y());
218 void KLineal::drawBackground(QPainter
& painter
) {
219 QColor a
, b
, bg
= mColor
;
220 QLinearGradient gradient
;
221 switch (mOrientation
) {
225 gradient
= QLinearGradient(1, 0, 1, height());
230 gradient
= QLinearGradient(1, 0, 1, height());
235 gradient
= QLinearGradient(0, 1, width(), 1);
240 gradient
= QLinearGradient(0, 1, width(), 1);
243 gradient
.setColorAt(0, a
);
244 gradient
.setColorAt(1, b
);
245 painter
.fillRect(rect(), QBrush(gradient
));
248 void KLineal::setOrientation(int inOrientation
) {
249 QRect r
= frameGeometry();
250 int nineties
= (int)inOrientation
- (int)mOrientation
;
251 QPoint center
= mLastClickPos
;
254 center
= mLastClickPos
;
257 center
= r
.topLeft()+QPoint(width()/2, height()/2);
260 rotateRect(r
, center
, nineties
);
262 QRect desktop
= KGlobalSettings::desktopGeometry(this);
263 if (r
.top() < desktop
.top())
264 r
.moveTop( desktop
.top() );
265 if (r
.bottom() > desktop
.bottom())
266 r
.moveBottom( desktop
.bottom() );
267 if (r
.left() < desktop
.left())
268 r
.moveLeft( desktop
.left() );
269 if (r
.right() > desktop
.right())
270 r
.moveRight( desktop
.right() );
273 mOrientation
= (inOrientation
+ 4) % 4;
274 switch(mOrientation
) {
276 mLabel
->move(4, height()-mLabel
->height()-4);
277 mColorLabel
->move(mLabel
->pos() + QPoint(0, -20));
278 mCurrentCursor
= mNorthCursor
;
282 mColorLabel
->move(mLabel
->pos() + QPoint(0, 20));
283 mCurrentCursor
= mSouthCursor
;
287 mColorLabel
->move(mLabel
->pos() + QPoint(0, 20));
288 mCurrentCursor
= mEastCursor
;
291 mLabel
->move(width()-mLabel
->width()-4, 4);
292 mColorLabel
->move(mLabel
->pos() + QPoint(-5, 20));
293 mCurrentCursor
= mWestCursor
;
297 if (mFullScreenAction
)
298 mFullScreenAction
->setText(mOrientation
% 2 ? i18n("&Full Screen Height") : i18n("&Full Screen Width"));
300 setCursor(mCurrentCursor
);
303 void KLineal::setNorth() {
304 setOrientation(North
);
306 void KLineal::setEast() {
307 setOrientation(East
);
309 void KLineal::setSouth() {
310 setOrientation(South
);
312 void KLineal::setWest() {
313 setOrientation(West
);
315 void KLineal::turnRight() {
316 setOrientation(mOrientation
- 1);
318 void KLineal::turnLeft() {
319 setOrientation(mOrientation
+ 1);
321 void KLineal::reLength(int percentOfScreen
) {
322 if (percentOfScreen
< 10) {
325 QRect r
= KGlobalSettings::desktopGeometry(this);
327 if (mOrientation
== North
|| mOrientation
== South
) {
328 mLongEdgeLen
= r
.width() * percentOfScreen
/ 100;
329 resize(mLongEdgeLen
, height());
331 mLongEdgeLen
= r
.height() * percentOfScreen
/ 100;
332 resize(width(), mLongEdgeLen
);
334 if (x()+width() < 10) {
337 if (y()+height() < 10) {
342 void KLineal::setShortLength() {
345 void KLineal::setMediumLength() {
348 void KLineal::setTallLength() {
351 void KLineal::setFullLength() {
354 void KLineal::choseColor() {
355 QRect r
= KGlobalSettings::desktopGeometry(this);
357 QPoint pos
= QCursor::pos();
358 if (pos
.x() + mColorSelector
.width() > r
.width()) {
359 pos
.setX(r
.width() - mColorSelector
.width());
361 if (pos
.y() + mColorSelector
.height() > r
.height()) {
362 pos
.setY(r
.height() - mColorSelector
.height());
364 mStoredColor
= mColor
;
365 mColorSelector
.move(pos
);
366 mColorSelector
.setColor(mColor
);
367 mColorSelector
.setDefaultColor( DEFAULT_RULER_COLOR
);
368 mColorSelector
.show();
370 connect(&mColorSelector
, SIGNAL(closeClicked()), this, SLOT(setColor()));
371 connect(&mColorSelector
, SIGNAL(colorSelected(const QColor
&)), this, SLOT(setColor(const QColor
&)));
373 connect(&mColorSelector, SIGNAL(cancelPressed()), this, SLOT(restoreColor()));
374 connect(&mColorSelector, SIGNAL(okPressed()), this, SLOT(saveColor()));
379 * slot to choose a font
381 void KLineal::choseFont() {
382 QFont font
= mScaleFont
;
383 int result
= KFontDialog::getFont(font
, false, this);
384 if (result
== KFontDialog::Accepted
) {
390 * set the ruler color to the previously selected color
392 void KLineal::setFont(QFont
&font
) {
400 * set the ruler color to the previously selected color
402 void KLineal::setColor() {
403 setColor(mColorSelector
.color());
408 * set the ruler color to some color
410 void KLineal::setColor(const QColor
&color
) {
412 if ( !mColor
.isValid() )
413 mColor
= DEFAULT_RULER_COLOR
;
419 * save the ruler color to the config file
421 void KLineal::saveSettings() {
422 KSharedConfig::Ptr cfg
= KGlobal::config(); // new KConfig(locateLocal("config", kapp->name()+"rc"));
424 QColor color
= mColor
;
425 KConfigGroup
cfgcg(cfg
, CFG_GROUP_SETTINGS
);
426 cfgcg
.writeEntry(QString(CFG_KEY_BGCOLOR
), color
);
427 cfgcg
.writeEntry(QString(CFG_KEY_SCALE_FONT
), mScaleFont
);
428 cfgcg
.writeEntry(QString(CFG_KEY_LENGTH
), mLongEdgeLen
);
436 void KLineal::restoreColor() {
437 setColor(mStoredColor
);
440 * lets the context menu appear at current cursor position
442 void KLineal::showMenu() {
443 QPoint pos
= QCursor::pos();
448 * overwritten to switch the value label and line cursor on
450 void KLineal::enterEvent(QEvent
* /*inEvent*/) {
451 if (!mDragging
) showLabel();
454 * overwritten to switch the value label and line cursor off
456 void KLineal::leaveEvent(QEvent
* /*inEvent*/) {
457 if (!geometry().contains(QCursor::pos())) {
462 * shows the value lable
464 void KLineal::showLabel() {
470 * hides the value label
472 void KLineal::hideLabel() {
477 * updates the current value label
479 void KLineal::adjustLabel() {
481 QPoint cpos
= QCursor::pos();
482 switch (mOrientation
) {
484 s
.sprintf("%d px", cpos
.x()-x());
487 s
.sprintf("%d px", cpos
.y()-y());
490 s
.sprintf("%d px", cpos
.y()-y());
493 s
.sprintf("%d px", cpos
.x()-x());
498 void KLineal::keyPressEvent(QKeyEvent
*e
) {
502 KToolInvocation::invokeHelp();
517 QWidget::keyPressEvent(e
);
520 if (e
->modifiers() & Qt::ShiftModifier
) {
524 KNotification::event(0, "cursormove", QString());
527 * overwritten to handle the line cursor which is a separate widget outside the main
528 * window. Also used for dragging.
530 void KLineal::mouseMoveEvent(QMouseEvent
* /*inEvent*/) {
531 if (mDragging
&& this == mouseGrabber()) {
532 move(QCursor::pos() - mDragOffset
);
534 QPoint p
= QCursor::pos();
535 switch (mOrientation
) {
549 // cerr << p.x()-x() << "," << p.y()-y() << ": " << KColorDialog::grabColor(p).name() << endl;
550 QColor color
= KColorDialog::grabColor(p
);
552 color
.getHsv(&h
, &s
, &v
);
553 mColorLabel
->setText(color
.name().toUpper());
554 QPalette palette
= mColorLabel
->palette();
555 palette
.setColor(mColorLabel
->backgroundRole(), color
);
561 color
.setHsv(h
, s
, v
);
562 palette
.setColor(mColorLabel
->foregroundRole(), color
);
563 mColorLabel
->setPalette(palette
);
569 * overwritten for dragging and contect menu
571 void KLineal::mousePressEvent(QMouseEvent
*inEvent
) {
572 mLastClickPos
= QCursor::pos();
575 QRect gr
= geometry();
576 mDragOffset
= mLastClickPos
- QPoint(gr
.left(), gr
.top());
577 if (inEvent
->button() == Qt::LeftButton
) {
579 grabMouse(Qt::SizeAllCursor
);
582 } else if (inEvent
->button() == Qt::MidButton
) {
585 } else if (inEvent
->button() == Qt::RightButton
) {
590 * overwritten for dragging
592 void KLineal::mouseReleaseEvent(QMouseEvent
* /*inEvent*/) {
600 * draws the scale according to the orientation
602 void KLineal::drawScale(QPainter
&painter
) {
603 painter
.setPen(Qt::black
);
604 QFont font
= mScaleFont
;
605 // font.setPixelSize(9);
606 painter
.setFont(font
);
607 QFontMetrics metrics
= painter
.fontMetrics();
614 // draw a frame around the whole thing
615 // (for some unknown reason, this doesn't show up anymore)
616 switch (mOrientation
) {
621 painter
.drawLine(0, 0, 0, h
-1);
622 painter
.drawLine(0, h
-1, w
-1, h
-1);
623 painter
.drawLine(w
-1, h
-1, w
-1, 0);
624 // painter.drawLine(width()-1, 0, 0, 0);
629 painter
.drawLine(0, 0, 0, h
-1);
630 painter
.drawLine(0, h
-1, w
-1, h
-1);
631 // painter.drawLine(width()-1, height()-1, width()-1, 0);
632 painter
.drawLine(w
-1, 0, 0, 0);
637 painter
.drawLine(0, 0, 0, h
-1);
638 // painter.drawLine(0, height()-1, width()-1, height()-1);
639 painter
.drawLine(w
-1, h
-1, w
-1, 0);
640 painter
.drawLine(w
-1, 0, 0, 0);
645 // painter.drawLine(0, 0, 0, height()-1);
646 painter
.drawLine(0, h
-1, w
-1, h
-1);
647 painter
.drawLine(w
-1, h
-1, w
-1, 0);
648 painter
.drawLine(w
-1, 0, 0, 0);
651 int ten
= 10, twenty
= 20, fourty
= 40, hundred
= 100;
652 for (longCoo
= 0; longCoo
< longLen
; longCoo
+=2) {
657 if (hundred
== 100) {
659 painter
.setFont(font
);
666 if (hundred
== 100 || mOrientation
== West
|| mOrientation
== East
) {
669 digits
= longCoo
% 100;
671 units
.sprintf("%d", digits
);
672 QSize textSize
= metrics
.size(Qt::TextSingleLine
, units
);
673 int tw
= textSize
.width();
674 int th
= textSize
.height();
675 switch (mOrientation
) {
677 if (digits
< 1000 || fourty
== 40 || hundred
== 100) {
679 painter
.drawText(longCoo
- tw
/2, shortStart
+ len
+ th
, units
);
681 painter
.drawText(1, shortStart
+ len
+ th
, units
);
686 if (digits
< 1000 || fourty
== 40 || hundred
== 100) {
688 painter
.drawText(longCoo
- tw
/2, shortStart
- len
- 2, units
);
690 painter
.drawText(1, shortStart
- len
- 2, units
);
696 painter
.drawText(shortStart
- len
- tw
- 2, longCoo
+ th
/2 - 2, units
);
698 painter
.drawText(shortStart
- len
- tw
- 2, th
-2, units
);
703 painter
.drawText(shortStart
+ len
+ 2, longCoo
+ th
/2 - 2, units
);
705 painter
.drawText(shortStart
+ len
+ 2, th
-2, units
);
713 switch(mOrientation
) {
715 painter
.drawLine(longCoo
, shortStart
, longCoo
, shortStart
+len
);
718 painter
.drawLine(longCoo
, shortStart
, longCoo
, shortStart
-len
);
721 painter
.drawLine(shortStart
, longCoo
, shortStart
-len
, longCoo
);
724 painter
.drawLine(shortStart
, longCoo
, shortStart
+len
, longCoo
);
727 ten
= (ten
== 10) ? 2: ten
+ 2;
728 twenty
= (twenty
== 20) ? 2: twenty
+ 2;
729 fourty
= (fourty
== 40) ? 2: fourty
+ 2;
730 if (hundred
== 100) {
733 painter
.setFont(font
);
740 * actually draws the ruler
742 void KLineal::paintEvent(QPaintEvent
* /*inEvent*/) {
745 drawBackground(painter
);
750 #include "klineal.moc"