File indexing completed on 2024-04-28 03:59:13
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1998 Jörg Habenicht <j.habenicht@europemail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kruler.h" 0009 0010 #include <QFont> 0011 #include <QPolygon> 0012 #include <QStylePainter> 0013 0014 #define INIT_VALUE 0 0015 #define INIT_MIN_VALUE 0 0016 #define INIT_MAX_VALUE 100 0017 #define INIT_TINY_MARK_DISTANCE 1 0018 #define INIT_LITTLE_MARK_DISTANCE 5 0019 #define INIT_MIDDLE_MARK_DISTANCE (INIT_LITTLE_MARK_DISTANCE * 2) 0020 #define INIT_BIG_MARK_DISTANCE (INIT_LITTLE_MARK_DISTANCE * 10) 0021 #define INIT_SHOW_TINY_MARK false 0022 #define INIT_SHOW_LITTLE_MARK true 0023 #define INIT_SHOW_MEDIUM_MARK true 0024 #define INIT_SHOW_BIG_MARK true 0025 #define INIT_SHOW_END_MARK true 0026 #define INIT_SHOW_POINTER true 0027 #define INIT_SHOW_END_LABEL true 0028 0029 #define INIT_PIXEL_PER_MARK (double)10.0 /* distance between 2 base marks in pixel */ 0030 #define INIT_OFFSET (-20) 0031 #define INIT_LENGTH_FIX true 0032 #define INIT_END_OFFSET 0 0033 0034 #define FIX_WIDTH 20 /* widget width in pixel */ 0035 #define LINE_END (FIX_WIDTH - 3) 0036 #define END_MARK_LENGTH (FIX_WIDTH - 6) 0037 #define END_MARK_X2 LINE_END 0038 #define END_MARK_X1 (END_MARK_X2 - END_MARK_LENGTH) 0039 #define BIG_MARK_LENGTH (END_MARK_LENGTH * 3 / 4) 0040 #define BIG_MARK_X2 LINE_END 0041 #define BIG_MARK_X1 (BIG_MARK_X2 - BIG_MARK_LENGTH) 0042 #define MIDDLE_MARK_LENGTH (END_MARK_LENGTH / 2) 0043 #define MIDDLE_MARK_X2 LINE_END 0044 #define MIDDLE_MARK_X1 (MIDDLE_MARK_X2 - MIDDLE_MARK_LENGTH) 0045 #define LITTLE_MARK_LENGTH (MIDDLE_MARK_LENGTH / 2) 0046 #define LITTLE_MARK_X2 LINE_END 0047 #define LITTLE_MARK_X1 (LITTLE_MARK_X2 - LITTLE_MARK_LENGTH) 0048 #define BASE_MARK_LENGTH (LITTLE_MARK_LENGTH / 2) 0049 #define BASE_MARK_X2 LINE_END 0050 #define BASE_MARK_X1 (BASE_MARK_X2 - BASE_MARK_LENGTH) 0051 0052 #define LABEL_SIZE 8 0053 #define END_LABEL_X 4 0054 #define END_LABEL_Y (END_LABEL_X + LABEL_SIZE - 2) 0055 0056 #undef PROFILING 0057 0058 #ifdef PROFILING 0059 #include <qdatetime.h> 0060 #endif 0061 0062 class KRulerPrivate 0063 { 0064 public: 0065 int endOffset_length; /* marks the offset at the end of the ruler 0066 * i.e. right side at horizontal and down side 0067 * at vertical rulers. 0068 * the ruler end mark is moved endOffset_length 0069 * ticks away from the widget end. 0070 * positive offset moves end mark inside the ruler. 0071 * if lengthFix is true, endOffset_length holds the 0072 * length of the ruler. 0073 */ 0074 int fontWidth; // ONLY valid for vertical rulers 0075 0076 QAbstractSlider range; 0077 Qt::Orientation dir; 0078 int tmDist; 0079 int lmDist; 0080 int mmDist; 0081 int bmDist; 0082 int offset; 0083 bool showtm : 1; /* show tiny, little, medium, big, endmarks */ 0084 bool showlm : 1; 0085 bool showmm : 1; 0086 bool showbm : 1; 0087 bool showem : 1; 0088 0089 bool showpointer : 1; 0090 bool showEndL : 1; 0091 bool lengthFix : 1; 0092 0093 double ppm; /* pixel per mark */ 0094 0095 QString endlabel; 0096 }; 0097 0098 KRuler::KRuler(QWidget *parent) 0099 : QAbstractSlider(parent) 0100 , d(new KRulerPrivate) 0101 { 0102 setRange(INIT_MIN_VALUE, INIT_MAX_VALUE); 0103 setPageStep(10); 0104 setValue(INIT_VALUE); 0105 initWidget(Qt::Horizontal); 0106 setFixedHeight(FIX_WIDTH); 0107 } 0108 0109 KRuler::KRuler(Qt::Orientation orient, QWidget *parent, Qt::WindowFlags f) 0110 : QAbstractSlider(parent) 0111 , d(new KRulerPrivate) 0112 { 0113 setRange(INIT_MIN_VALUE, INIT_MAX_VALUE); 0114 setPageStep(10); 0115 setValue(INIT_VALUE); 0116 setWindowFlags(f); 0117 initWidget(orient); 0118 if (orient == Qt::Horizontal) { 0119 setFixedHeight(FIX_WIDTH); 0120 } else { 0121 setFixedWidth(FIX_WIDTH); 0122 } 0123 } 0124 0125 KRuler::KRuler(Qt::Orientation orient, int widgetWidth, QWidget *parent, Qt::WindowFlags f) 0126 : QAbstractSlider(parent) 0127 , d(new KRulerPrivate) 0128 { 0129 setRange(INIT_MIN_VALUE, INIT_MAX_VALUE); 0130 setPageStep(10); 0131 setValue(INIT_VALUE); 0132 setWindowFlags(f); 0133 initWidget(orient); 0134 if (orient == Qt::Horizontal) { 0135 setFixedHeight(widgetWidth); 0136 } else { 0137 setFixedWidth(widgetWidth); 0138 } 0139 } 0140 0141 void KRuler::initWidget(Qt::Orientation orientation) 0142 { 0143 d->showpointer = INIT_SHOW_POINTER; 0144 d->showEndL = INIT_SHOW_END_LABEL; 0145 d->lengthFix = INIT_LENGTH_FIX; 0146 d->endOffset_length = INIT_END_OFFSET; 0147 0148 d->tmDist = INIT_TINY_MARK_DISTANCE; 0149 d->lmDist = INIT_LITTLE_MARK_DISTANCE; 0150 d->mmDist = INIT_MIDDLE_MARK_DISTANCE; 0151 d->bmDist = INIT_BIG_MARK_DISTANCE; 0152 d->offset = INIT_OFFSET; 0153 d->showtm = INIT_SHOW_TINY_MARK; 0154 d->showlm = INIT_SHOW_LITTLE_MARK; 0155 d->showmm = INIT_SHOW_MEDIUM_MARK; 0156 d->showbm = INIT_SHOW_BIG_MARK; 0157 d->showem = INIT_SHOW_END_MARK; 0158 d->ppm = INIT_PIXEL_PER_MARK; 0159 d->dir = orientation; 0160 } 0161 0162 KRuler::~KRuler() = default; 0163 0164 void KRuler::setTinyMarkDistance(int dist) 0165 { 0166 if (dist != d->tmDist) { 0167 d->tmDist = dist; 0168 update(contentsRect()); 0169 } 0170 } 0171 0172 int KRuler::tinyMarkDistance() const 0173 { 0174 return d->tmDist; 0175 } 0176 0177 void KRuler::setLittleMarkDistance(int dist) 0178 { 0179 if (dist != d->lmDist) { 0180 d->lmDist = dist; 0181 update(contentsRect()); 0182 } 0183 } 0184 0185 int KRuler::littleMarkDistance() const 0186 { 0187 return d->lmDist; 0188 } 0189 0190 void KRuler::setMediumMarkDistance(int dist) 0191 { 0192 if (dist != d->mmDist) { 0193 d->mmDist = dist; 0194 update(contentsRect()); 0195 } 0196 } 0197 0198 int KRuler::mediumMarkDistance() const 0199 { 0200 return d->mmDist; 0201 } 0202 0203 void KRuler::setBigMarkDistance(int dist) 0204 { 0205 if (dist != d->bmDist) { 0206 d->bmDist = dist; 0207 update(contentsRect()); 0208 } 0209 } 0210 0211 int KRuler::bigMarkDistance() const 0212 { 0213 return d->bmDist; 0214 } 0215 0216 void KRuler::setShowTinyMarks(bool show) 0217 { 0218 if (show != d->showtm) { 0219 d->showtm = show; 0220 update(contentsRect()); 0221 } 0222 } 0223 0224 bool KRuler::showTinyMarks() const 0225 { 0226 return d->showtm; 0227 } 0228 0229 void KRuler::setShowLittleMarks(bool show) 0230 { 0231 if (show != d->showlm) { 0232 d->showlm = show; 0233 update(contentsRect()); 0234 } 0235 } 0236 0237 bool KRuler::showLittleMarks() const 0238 { 0239 return d->showlm; 0240 } 0241 0242 void KRuler::setShowMediumMarks(bool show) 0243 { 0244 if (show != d->showmm) { 0245 d->showmm = show; 0246 update(contentsRect()); 0247 } 0248 } 0249 0250 bool KRuler::showMediumMarks() const 0251 { 0252 return d->showmm; 0253 } 0254 0255 void KRuler::setShowBigMarks(bool show) 0256 { 0257 if (show != d->showbm) { 0258 d->showbm = show; 0259 update(contentsRect()); 0260 } 0261 } 0262 0263 bool KRuler::showBigMarks() const 0264 { 0265 return d->showbm; 0266 } 0267 0268 void KRuler::setShowEndMarks(bool show) 0269 { 0270 if (show != d->showem) { 0271 d->showem = show; 0272 update(contentsRect()); 0273 } 0274 } 0275 0276 bool KRuler::showEndMarks() const 0277 { 0278 return d->showem; 0279 } 0280 0281 void KRuler::setShowPointer(bool show) 0282 { 0283 if (show != d->showpointer) { 0284 d->showpointer = show; 0285 update(contentsRect()); 0286 } 0287 } 0288 0289 bool KRuler::showPointer() const 0290 { 0291 return d->showpointer; 0292 } 0293 0294 void KRuler::setShowEndLabel(bool show) 0295 { 0296 if (d->showEndL != show) { 0297 d->showEndL = show; 0298 update(contentsRect()); 0299 } 0300 } 0301 0302 bool KRuler::showEndLabel() const 0303 { 0304 return d->showEndL; 0305 } 0306 0307 void KRuler::setEndLabel(const QString &label) 0308 { 0309 d->endlabel = label; 0310 0311 // premeasure the fontwidth and save it 0312 if (d->dir == Qt::Vertical) { 0313 QFont font = this->font(); 0314 font.setPointSize(LABEL_SIZE); 0315 QFontMetrics fm(font); 0316 d->fontWidth = fm.horizontalAdvance(d->endlabel); 0317 } 0318 update(contentsRect()); 0319 } 0320 0321 QString KRuler::endLabel() const 0322 { 0323 return d->endlabel; 0324 } 0325 0326 void KRuler::setRulerMetricStyle(KRuler::MetricStyle style) 0327 { 0328 switch (style) { 0329 default: /* fall through */ 0330 case Custom: 0331 return; 0332 case Pixel: 0333 setLittleMarkDistance(1); 0334 setMediumMarkDistance(5); 0335 setBigMarkDistance(10); 0336 0337 setShowTinyMarks(false); 0338 setShowLittleMarks(true); 0339 setShowMediumMarks(true); 0340 setShowBigMarks(true); 0341 setShowEndMarks(true); 0342 0343 update(contentsRect()); 0344 setPixelPerMark(10.0); 0345 0346 break; 0347 case Inch: 0348 setTinyMarkDistance(1); 0349 setLittleMarkDistance(2); 0350 setMediumMarkDistance(4); 0351 setBigMarkDistance(8); 0352 0353 setShowTinyMarks(true); 0354 setShowLittleMarks(true); 0355 setShowMediumMarks(true); 0356 setShowBigMarks(true); 0357 setShowEndMarks(true); 0358 0359 update(contentsRect()); 0360 setPixelPerMark(9.0); 0361 0362 break; 0363 case Millimetres: /* fall through */ 0364 case Centimetres: /* fall through */ 0365 case Metres: 0366 setLittleMarkDistance(1); 0367 setMediumMarkDistance(5); 0368 setBigMarkDistance(10); 0369 0370 setShowTinyMarks(false); 0371 setShowLittleMarks(true); 0372 setShowMediumMarks(true); 0373 setShowBigMarks(true); 0374 setShowEndMarks(true); 0375 0376 update(contentsRect()); 0377 setPixelPerMark(3.0); 0378 } 0379 switch (style) { 0380 case Pixel: 0381 setEndLabel(QStringLiteral("pixel")); 0382 break; 0383 case Inch: 0384 setEndLabel(QStringLiteral("inch")); 0385 break; 0386 case Millimetres: 0387 setEndLabel(QStringLiteral("mm")); 0388 break; 0389 case Centimetres: 0390 setEndLabel(QStringLiteral("cm")); 0391 break; 0392 case Metres: 0393 setEndLabel(QStringLiteral("m")); 0394 default: /* never reached, see above switch */ 0395 /* empty command */; 0396 } 0397 // if the style changes one of the values, 0398 // update would have been called inside the methods 0399 // -> no update() call needed here ! 0400 } 0401 0402 void KRuler::setPixelPerMark(double rate) 0403 { 0404 // never compare floats against each other :) 0405 d->ppm = rate; 0406 update(contentsRect()); 0407 } 0408 0409 double KRuler::pixelPerMark() const 0410 { 0411 return d->ppm; 0412 } 0413 0414 void KRuler::setLength(int length) 0415 { 0416 int tmp; 0417 if (d->lengthFix) { 0418 tmp = length; 0419 } else { 0420 tmp = width() - length; 0421 } 0422 if (tmp != d->endOffset_length) { 0423 d->endOffset_length = tmp; 0424 update(contentsRect()); 0425 } 0426 } 0427 0428 int KRuler::length() const 0429 { 0430 if (d->lengthFix) { 0431 return d->endOffset_length; 0432 } 0433 return (width() - d->endOffset_length); 0434 } 0435 0436 void KRuler::setLengthFixed(bool fix) 0437 { 0438 d->lengthFix = fix; 0439 } 0440 0441 bool KRuler::lengthFixed() const 0442 { 0443 return d->lengthFix; 0444 } 0445 0446 void KRuler::setOffset(int _offset) 0447 { 0448 // debug("set offset %i", _offset); 0449 if (d->offset != _offset) { 0450 d->offset = _offset; 0451 update(contentsRect()); 0452 } 0453 } 0454 0455 int KRuler::offset() const 0456 { 0457 return d->offset; 0458 } 0459 0460 int KRuler::endOffset() const 0461 { 0462 if (d->lengthFix) { 0463 return (width() - d->endOffset_length); 0464 } 0465 return d->endOffset_length; 0466 } 0467 0468 void KRuler::slideUp(int count) 0469 { 0470 if (count) { 0471 d->offset += count; 0472 update(contentsRect()); 0473 } 0474 } 0475 0476 void KRuler::slideDown(int count) 0477 { 0478 if (count) { 0479 d->offset -= count; 0480 update(contentsRect()); 0481 } 0482 } 0483 0484 void KRuler::slotNewValue(int _value) 0485 { 0486 int oldvalue = value(); 0487 if (oldvalue == _value) { 0488 return; 0489 } 0490 // setValue(_value); 0491 setValue(_value); 0492 if (value() == oldvalue) { 0493 return; 0494 } 0495 // get the rectangular of the old and the new ruler pointer 0496 // and repaint only him 0497 if (d->dir == Qt::Horizontal) { 0498 QRect oldrec(-5 + oldvalue, 10, 11, 6); 0499 QRect newrec(-5 + _value, 10, 11, 6); 0500 repaint(oldrec.united(newrec)); 0501 } else { 0502 QRect oldrec(10, -5 + oldvalue, 6, 11); 0503 QRect newrec(10, -5 + _value, 6, 11); 0504 repaint(oldrec.united(newrec)); 0505 } 0506 } 0507 0508 void KRuler::slotNewOffset(int _offset) 0509 { 0510 if (d->offset != _offset) { 0511 // setOffset(_offset); 0512 d->offset = _offset; 0513 repaint(contentsRect()); 0514 } 0515 } 0516 0517 void KRuler::slotEndOffset(int offset) 0518 { 0519 int tmp; 0520 if (d->lengthFix) { 0521 tmp = width() - offset; 0522 } else { 0523 tmp = offset; 0524 } 0525 if (d->endOffset_length != tmp) { 0526 d->endOffset_length = tmp; 0527 repaint(contentsRect()); 0528 } 0529 } 0530 0531 void KRuler::paintEvent(QPaintEvent * /*e*/) 0532 { 0533 // debug ("KRuler::drawContents, %s",(horizontal==dir)?"horizontal":"vertical"); 0534 0535 QStylePainter p(this); 0536 #ifdef PROFILING 0537 QTime time; 0538 time.start(); 0539 for (int profile = 0; profile < 10; profile++) { 0540 #endif 0541 0542 int value = this->value(); 0543 int minval = minimum(); 0544 int maxval; 0545 if (d->dir == Qt::Horizontal) { 0546 maxval = maximum() + d->offset - (d->lengthFix ? (height() - d->endOffset_length) : d->endOffset_length); 0547 } else { 0548 maxval = maximum() + d->offset - (d->lengthFix ? (width() - d->endOffset_length) : d->endOffset_length); 0549 } 0550 // ioffsetval = value-offset; 0551 // pixelpm = (int)ppm; 0552 // left = clip.left(), 0553 // right = clip.right(); 0554 double f; 0555 double fend; 0556 double offsetmin = (double)(minval - d->offset); 0557 double offsetmax = (double)(maxval - d->offset); 0558 double fontOffset = (((double)minval) > offsetmin) ? (double)minval : offsetmin; 0559 0560 // draw labels 0561 QFont font = p.font(); 0562 font.setPointSize(LABEL_SIZE); 0563 p.setFont(font); 0564 // draw littlemarklabel 0565 0566 // draw mediummarklabel 0567 0568 // draw bigmarklabel 0569 0570 // draw endlabel 0571 if (d->showEndL) { 0572 if (d->dir == Qt::Horizontal) { 0573 p.translate(fontOffset, 0); 0574 p.drawText(END_LABEL_X, END_LABEL_Y, d->endlabel); 0575 } else { // rotate text +pi/2 and move down a bit 0576 // QFontMetrics fm(font); 0577 #ifdef KRULER_ROTATE_TEST 0578 p.rotate(-90.0 + rotate); 0579 p.translate(-8.0 - fontOffset - d->fontWidth + xtrans, ytrans); 0580 #else 0581 p.rotate(-90.0); 0582 p.translate(-8.0 - fontOffset - d->fontWidth, 0.0); 0583 #endif 0584 p.drawText(END_LABEL_X, END_LABEL_Y, d->endlabel); 0585 } 0586 p.resetTransform(); 0587 } 0588 0589 // draw the tiny marks 0590 if (d->showtm) { 0591 fend = d->ppm * d->tmDist; 0592 for (f = offsetmin; f < offsetmax; f += fend) { 0593 if (d->dir == Qt::Horizontal) { 0594 p.drawLine((int)f, BASE_MARK_X1, (int)f, BASE_MARK_X2); 0595 } else { 0596 p.drawLine(BASE_MARK_X1, (int)f, BASE_MARK_X2, (int)f); 0597 } 0598 } 0599 } 0600 if (d->showlm) { 0601 // draw the little marks 0602 fend = d->ppm * d->lmDist; 0603 for (f = offsetmin; f < offsetmax; f += fend) { 0604 if (d->dir == Qt::Horizontal) { 0605 p.drawLine((int)f, LITTLE_MARK_X1, (int)f, LITTLE_MARK_X2); 0606 } else { 0607 p.drawLine(LITTLE_MARK_X1, (int)f, LITTLE_MARK_X2, (int)f); 0608 } 0609 } 0610 } 0611 if (d->showmm) { 0612 // draw medium marks 0613 fend = d->ppm * d->mmDist; 0614 for (f = offsetmin; f < offsetmax; f += fend) { 0615 if (d->dir == Qt::Horizontal) { 0616 p.drawLine((int)f, MIDDLE_MARK_X1, (int)f, MIDDLE_MARK_X2); 0617 } else { 0618 p.drawLine(MIDDLE_MARK_X1, (int)f, MIDDLE_MARK_X2, (int)f); 0619 } 0620 } 0621 } 0622 if (d->showbm) { 0623 // draw big marks 0624 fend = d->ppm * d->bmDist; 0625 for (f = offsetmin; f < offsetmax; f += fend) { 0626 if (d->dir == Qt::Horizontal) { 0627 p.drawLine((int)f, BIG_MARK_X1, (int)f, BIG_MARK_X2); 0628 } else { 0629 p.drawLine(BIG_MARK_X1, (int)f, BIG_MARK_X2, (int)f); 0630 } 0631 } 0632 } 0633 if (d->showem) { 0634 // draw end marks 0635 if (d->dir == Qt::Horizontal) { 0636 p.drawLine(minval - d->offset, END_MARK_X1, minval - d->offset, END_MARK_X2); 0637 p.drawLine(maxval - d->offset, END_MARK_X1, maxval - d->offset, END_MARK_X2); 0638 } else { 0639 p.drawLine(END_MARK_X1, minval - d->offset, END_MARK_X2, minval - d->offset); 0640 p.drawLine(END_MARK_X1, maxval - d->offset, END_MARK_X2, maxval - d->offset); 0641 } 0642 } 0643 0644 // draw pointer 0645 if (d->showpointer) { 0646 QPolygon pa(4); 0647 if (d->dir == Qt::Horizontal) { 0648 pa.setPoints(3, value - 5, 10, value + 5, 10, value /*+0*/, 15); 0649 } else { 0650 pa.setPoints(3, 10, value - 5, 10, value + 5, 15, value /*+0*/); 0651 } 0652 p.setBrush(p.background().color()); 0653 p.drawPolygon(pa); 0654 } 0655 0656 #ifdef PROFILING 0657 } 0658 int elapsed = time.elapsed(); 0659 debug("paint time %i", elapsed); 0660 #endif 0661 } 0662 0663 #include "moc_kruler.cpp"