File indexing completed on 2025-02-02 14:20:10
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 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 0) 0165 void KRuler::setMinValue(int value) 0166 { 0167 setMinimum(value); 0168 } 0169 #endif 0170 0171 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 0) 0172 int KRuler::minValue() const 0173 { 0174 return minimum(); 0175 } 0176 #endif 0177 0178 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 0) 0179 void KRuler::setMaxValue(int value) 0180 { 0181 setMaximum(value); 0182 } 0183 #endif 0184 0185 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 0) 0186 int KRuler::maxValue() const 0187 { 0188 return maximum(); 0189 } 0190 #endif 0191 0192 void KRuler::setTinyMarkDistance(int dist) 0193 { 0194 if (dist != d->tmDist) { 0195 d->tmDist = dist; 0196 update(contentsRect()); 0197 } 0198 } 0199 0200 int KRuler::tinyMarkDistance() const 0201 { 0202 return d->tmDist; 0203 } 0204 0205 void KRuler::setLittleMarkDistance(int dist) 0206 { 0207 if (dist != d->lmDist) { 0208 d->lmDist = dist; 0209 update(contentsRect()); 0210 } 0211 } 0212 0213 int KRuler::littleMarkDistance() const 0214 { 0215 return d->lmDist; 0216 } 0217 0218 void KRuler::setMediumMarkDistance(int dist) 0219 { 0220 if (dist != d->mmDist) { 0221 d->mmDist = dist; 0222 update(contentsRect()); 0223 } 0224 } 0225 0226 int KRuler::mediumMarkDistance() const 0227 { 0228 return d->mmDist; 0229 } 0230 0231 void KRuler::setBigMarkDistance(int dist) 0232 { 0233 if (dist != d->bmDist) { 0234 d->bmDist = dist; 0235 update(contentsRect()); 0236 } 0237 } 0238 0239 int KRuler::bigMarkDistance() const 0240 { 0241 return d->bmDist; 0242 } 0243 0244 void KRuler::setShowTinyMarks(bool show) 0245 { 0246 if (show != d->showtm) { 0247 d->showtm = show; 0248 update(contentsRect()); 0249 } 0250 } 0251 0252 bool KRuler::showTinyMarks() const 0253 { 0254 return d->showtm; 0255 } 0256 0257 void KRuler::setShowLittleMarks(bool show) 0258 { 0259 if (show != d->showlm) { 0260 d->showlm = show; 0261 update(contentsRect()); 0262 } 0263 } 0264 0265 bool KRuler::showLittleMarks() const 0266 { 0267 return d->showlm; 0268 } 0269 0270 void KRuler::setShowMediumMarks(bool show) 0271 { 0272 if (show != d->showmm) { 0273 d->showmm = show; 0274 update(contentsRect()); 0275 } 0276 } 0277 0278 bool KRuler::showMediumMarks() const 0279 { 0280 return d->showmm; 0281 } 0282 0283 void KRuler::setShowBigMarks(bool show) 0284 { 0285 if (show != d->showbm) { 0286 d->showbm = show; 0287 update(contentsRect()); 0288 } 0289 } 0290 0291 bool KRuler::showBigMarks() const 0292 { 0293 return d->showbm; 0294 } 0295 0296 void KRuler::setShowEndMarks(bool show) 0297 { 0298 if (show != d->showem) { 0299 d->showem = show; 0300 update(contentsRect()); 0301 } 0302 } 0303 0304 bool KRuler::showEndMarks() const 0305 { 0306 return d->showem; 0307 } 0308 0309 void KRuler::setShowPointer(bool show) 0310 { 0311 if (show != d->showpointer) { 0312 d->showpointer = show; 0313 update(contentsRect()); 0314 } 0315 } 0316 0317 bool KRuler::showPointer() const 0318 { 0319 return d->showpointer; 0320 } 0321 0322 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 0) 0323 void KRuler::setFrameStyle(int) 0324 { 0325 } 0326 #endif 0327 0328 void KRuler::setShowEndLabel(bool show) 0329 { 0330 if (d->showEndL != show) { 0331 d->showEndL = show; 0332 update(contentsRect()); 0333 } 0334 } 0335 0336 bool KRuler::showEndLabel() const 0337 { 0338 return d->showEndL; 0339 } 0340 0341 void KRuler::setEndLabel(const QString &label) 0342 { 0343 d->endlabel = label; 0344 0345 // premeasure the fontwidth and save it 0346 if (d->dir == Qt::Vertical) { 0347 QFont font = this->font(); 0348 font.setPointSize(LABEL_SIZE); 0349 QFontMetrics fm(font); 0350 d->fontWidth = fm.horizontalAdvance(d->endlabel); 0351 } 0352 update(contentsRect()); 0353 } 0354 0355 QString KRuler::endLabel() const 0356 { 0357 return d->endlabel; 0358 } 0359 0360 void KRuler::setRulerMetricStyle(KRuler::MetricStyle style) 0361 { 0362 switch (style) { 0363 default: /* fall through */ 0364 case Custom: 0365 return; 0366 case Pixel: 0367 setLittleMarkDistance(1); 0368 setMediumMarkDistance(5); 0369 setBigMarkDistance(10); 0370 0371 setShowTinyMarks(false); 0372 setShowLittleMarks(true); 0373 setShowMediumMarks(true); 0374 setShowBigMarks(true); 0375 setShowEndMarks(true); 0376 0377 update(contentsRect()); 0378 setPixelPerMark(10.0); 0379 0380 break; 0381 case Inch: 0382 setTinyMarkDistance(1); 0383 setLittleMarkDistance(2); 0384 setMediumMarkDistance(4); 0385 setBigMarkDistance(8); 0386 0387 setShowTinyMarks(true); 0388 setShowLittleMarks(true); 0389 setShowMediumMarks(true); 0390 setShowBigMarks(true); 0391 setShowEndMarks(true); 0392 0393 update(contentsRect()); 0394 setPixelPerMark(9.0); 0395 0396 break; 0397 case Millimetres: /* fall through */ 0398 case Centimetres: /* fall through */ 0399 case Metres: 0400 setLittleMarkDistance(1); 0401 setMediumMarkDistance(5); 0402 setBigMarkDistance(10); 0403 0404 setShowTinyMarks(false); 0405 setShowLittleMarks(true); 0406 setShowMediumMarks(true); 0407 setShowBigMarks(true); 0408 setShowEndMarks(true); 0409 0410 update(contentsRect()); 0411 setPixelPerMark(3.0); 0412 } 0413 switch (style) { 0414 case Pixel: 0415 setEndLabel(QStringLiteral("pixel")); 0416 break; 0417 case Inch: 0418 setEndLabel(QStringLiteral("inch")); 0419 break; 0420 case Millimetres: 0421 setEndLabel(QStringLiteral("mm")); 0422 break; 0423 case Centimetres: 0424 setEndLabel(QStringLiteral("cm")); 0425 break; 0426 case Metres: 0427 setEndLabel(QStringLiteral("m")); 0428 default: /* never reached, see above switch */ 0429 /* empty command */; 0430 } 0431 // if the style changes one of the values, 0432 // update would have been called inside the methods 0433 // -> no update() call needed here ! 0434 } 0435 0436 void KRuler::setPixelPerMark(double rate) 0437 { 0438 // never compare floats against each other :) 0439 d->ppm = rate; 0440 update(contentsRect()); 0441 } 0442 0443 double KRuler::pixelPerMark() const 0444 { 0445 return d->ppm; 0446 } 0447 0448 void KRuler::setLength(int length) 0449 { 0450 int tmp; 0451 if (d->lengthFix) { 0452 tmp = length; 0453 } else { 0454 tmp = width() - length; 0455 } 0456 if (tmp != d->endOffset_length) { 0457 d->endOffset_length = tmp; 0458 update(contentsRect()); 0459 } 0460 } 0461 0462 int KRuler::length() const 0463 { 0464 if (d->lengthFix) { 0465 return d->endOffset_length; 0466 } 0467 return (width() - d->endOffset_length); 0468 } 0469 0470 void KRuler::setLengthFixed(bool fix) 0471 { 0472 d->lengthFix = fix; 0473 } 0474 0475 bool KRuler::lengthFixed() const 0476 { 0477 return d->lengthFix; 0478 } 0479 0480 void KRuler::setOffset(int _offset) 0481 { 0482 // debug("set offset %i", _offset); 0483 if (d->offset != _offset) { 0484 d->offset = _offset; 0485 update(contentsRect()); 0486 } 0487 } 0488 0489 int KRuler::offset() const 0490 { 0491 return d->offset; 0492 } 0493 0494 int KRuler::endOffset() const 0495 { 0496 if (d->lengthFix) { 0497 return (width() - d->endOffset_length); 0498 } 0499 return d->endOffset_length; 0500 } 0501 0502 void KRuler::slideUp(int count) 0503 { 0504 if (count) { 0505 d->offset += count; 0506 update(contentsRect()); 0507 } 0508 } 0509 0510 void KRuler::slideDown(int count) 0511 { 0512 if (count) { 0513 d->offset -= count; 0514 update(contentsRect()); 0515 } 0516 } 0517 0518 void KRuler::slotNewValue(int _value) 0519 { 0520 int oldvalue = value(); 0521 if (oldvalue == _value) { 0522 return; 0523 } 0524 // setValue(_value); 0525 setValue(_value); 0526 if (value() == oldvalue) { 0527 return; 0528 } 0529 // get the rectangular of the old and the new ruler pointer 0530 // and repaint only him 0531 if (d->dir == Qt::Horizontal) { 0532 QRect oldrec(-5 + oldvalue, 10, 11, 6); 0533 QRect newrec(-5 + _value, 10, 11, 6); 0534 repaint(oldrec.united(newrec)); 0535 } else { 0536 QRect oldrec(10, -5 + oldvalue, 6, 11); 0537 QRect newrec(10, -5 + _value, 6, 11); 0538 repaint(oldrec.united(newrec)); 0539 } 0540 } 0541 0542 void KRuler::slotNewOffset(int _offset) 0543 { 0544 if (d->offset != _offset) { 0545 // setOffset(_offset); 0546 d->offset = _offset; 0547 repaint(contentsRect()); 0548 } 0549 } 0550 0551 void KRuler::slotEndOffset(int offset) 0552 { 0553 int tmp; 0554 if (d->lengthFix) { 0555 tmp = width() - offset; 0556 } else { 0557 tmp = offset; 0558 } 0559 if (d->endOffset_length != tmp) { 0560 d->endOffset_length = tmp; 0561 repaint(contentsRect()); 0562 } 0563 } 0564 0565 void KRuler::paintEvent(QPaintEvent * /*e*/) 0566 { 0567 // debug ("KRuler::drawContents, %s",(horizontal==dir)?"horizontal":"vertical"); 0568 0569 QStylePainter p(this); 0570 #ifdef PROFILING 0571 QTime time; 0572 time.start(); 0573 for (int profile = 0; profile < 10; profile++) { 0574 #endif 0575 0576 int value = this->value(); 0577 int minval = minimum(); 0578 int maxval; 0579 if (d->dir == Qt::Horizontal) { 0580 maxval = maximum() + d->offset - (d->lengthFix ? (height() - d->endOffset_length) : d->endOffset_length); 0581 } else { 0582 maxval = maximum() + d->offset - (d->lengthFix ? (width() - d->endOffset_length) : d->endOffset_length); 0583 } 0584 // ioffsetval = value-offset; 0585 // pixelpm = (int)ppm; 0586 // left = clip.left(), 0587 // right = clip.right(); 0588 double f; 0589 double fend; 0590 double offsetmin = (double)(minval - d->offset); 0591 double offsetmax = (double)(maxval - d->offset); 0592 double fontOffset = (((double)minval) > offsetmin) ? (double)minval : offsetmin; 0593 0594 // draw labels 0595 QFont font = p.font(); 0596 font.setPointSize(LABEL_SIZE); 0597 p.setFont(font); 0598 // draw littlemarklabel 0599 0600 // draw mediummarklabel 0601 0602 // draw bigmarklabel 0603 0604 // draw endlabel 0605 if (d->showEndL) { 0606 if (d->dir == Qt::Horizontal) { 0607 p.translate(fontOffset, 0); 0608 p.drawText(END_LABEL_X, END_LABEL_Y, d->endlabel); 0609 } else { // rotate text +pi/2 and move down a bit 0610 // QFontMetrics fm(font); 0611 #ifdef KRULER_ROTATE_TEST 0612 p.rotate(-90.0 + rotate); 0613 p.translate(-8.0 - fontOffset - d->fontWidth + xtrans, ytrans); 0614 #else 0615 p.rotate(-90.0); 0616 p.translate(-8.0 - fontOffset - d->fontWidth, 0.0); 0617 #endif 0618 p.drawText(END_LABEL_X, END_LABEL_Y, d->endlabel); 0619 } 0620 p.resetTransform(); 0621 } 0622 0623 // draw the tiny marks 0624 if (d->showtm) { 0625 fend = d->ppm * d->tmDist; 0626 for (f = offsetmin; f < offsetmax; f += fend) { 0627 if (d->dir == Qt::Horizontal) { 0628 p.drawLine((int)f, BASE_MARK_X1, (int)f, BASE_MARK_X2); 0629 } else { 0630 p.drawLine(BASE_MARK_X1, (int)f, BASE_MARK_X2, (int)f); 0631 } 0632 } 0633 } 0634 if (d->showlm) { 0635 // draw the little marks 0636 fend = d->ppm * d->lmDist; 0637 for (f = offsetmin; f < offsetmax; f += fend) { 0638 if (d->dir == Qt::Horizontal) { 0639 p.drawLine((int)f, LITTLE_MARK_X1, (int)f, LITTLE_MARK_X2); 0640 } else { 0641 p.drawLine(LITTLE_MARK_X1, (int)f, LITTLE_MARK_X2, (int)f); 0642 } 0643 } 0644 } 0645 if (d->showmm) { 0646 // draw medium marks 0647 fend = d->ppm * d->mmDist; 0648 for (f = offsetmin; f < offsetmax; f += fend) { 0649 if (d->dir == Qt::Horizontal) { 0650 p.drawLine((int)f, MIDDLE_MARK_X1, (int)f, MIDDLE_MARK_X2); 0651 } else { 0652 p.drawLine(MIDDLE_MARK_X1, (int)f, MIDDLE_MARK_X2, (int)f); 0653 } 0654 } 0655 } 0656 if (d->showbm) { 0657 // draw big marks 0658 fend = d->ppm * d->bmDist; 0659 for (f = offsetmin; f < offsetmax; f += fend) { 0660 if (d->dir == Qt::Horizontal) { 0661 p.drawLine((int)f, BIG_MARK_X1, (int)f, BIG_MARK_X2); 0662 } else { 0663 p.drawLine(BIG_MARK_X1, (int)f, BIG_MARK_X2, (int)f); 0664 } 0665 } 0666 } 0667 if (d->showem) { 0668 // draw end marks 0669 if (d->dir == Qt::Horizontal) { 0670 p.drawLine(minval - d->offset, END_MARK_X1, minval - d->offset, END_MARK_X2); 0671 p.drawLine(maxval - d->offset, END_MARK_X1, maxval - d->offset, END_MARK_X2); 0672 } else { 0673 p.drawLine(END_MARK_X1, minval - d->offset, END_MARK_X2, minval - d->offset); 0674 p.drawLine(END_MARK_X1, maxval - d->offset, END_MARK_X2, maxval - d->offset); 0675 } 0676 } 0677 0678 // draw pointer 0679 if (d->showpointer) { 0680 QPolygon pa(4); 0681 if (d->dir == Qt::Horizontal) { 0682 pa.setPoints(3, value - 5, 10, value + 5, 10, value /*+0*/, 15); 0683 } else { 0684 pa.setPoints(3, 10, value - 5, 10, value + 5, 15, value /*+0*/); 0685 } 0686 p.setBrush(p.background().color()); 0687 p.drawPolygon(pa); 0688 } 0689 0690 #ifdef PROFILING 0691 } 0692 int elapsed = time.elapsed(); 0693 debug("paint time %i", elapsed); 0694 #endif 0695 } 0696 0697 #include "moc_kruler.cpp"