/* This file is part of the KDE libraries SPDX-FileCopyrightText: 1998 Jörg Habenicht SPDX-License-Identifier: LGPL-2.0-or-later */ #include "kruler.h" #include #include #include #define INIT_VALUE 0 #define INIT_MIN_VALUE 0 #define INIT_MAX_VALUE 100 #define INIT_TINY_MARK_DISTANCE 1 #define INIT_LITTLE_MARK_DISTANCE 5 #define INIT_MIDDLE_MARK_DISTANCE (INIT_LITTLE_MARK_DISTANCE * 2) #define INIT_BIG_MARK_DISTANCE (INIT_LITTLE_MARK_DISTANCE * 10) #define INIT_SHOW_TINY_MARK false #define INIT_SHOW_LITTLE_MARK true #define INIT_SHOW_MEDIUM_MARK true #define INIT_SHOW_BIG_MARK true #define INIT_SHOW_END_MARK true #define INIT_SHOW_POINTER true #define INIT_SHOW_END_LABEL true #define INIT_PIXEL_PER_MARK (double)10.0 /* distance between 2 base marks in pixel */ #define INIT_OFFSET (-20) #define INIT_LENGTH_FIX true #define INIT_END_OFFSET 0 #define FIX_WIDTH 20 /* widget width in pixel */ #define LINE_END (FIX_WIDTH - 3) #define END_MARK_LENGTH (FIX_WIDTH - 6) #define END_MARK_X2 LINE_END #define END_MARK_X1 (END_MARK_X2 - END_MARK_LENGTH) #define BIG_MARK_LENGTH (END_MARK_LENGTH * 3 / 4) #define BIG_MARK_X2 LINE_END #define BIG_MARK_X1 (BIG_MARK_X2 - BIG_MARK_LENGTH) #define MIDDLE_MARK_LENGTH (END_MARK_LENGTH / 2) #define MIDDLE_MARK_X2 LINE_END #define MIDDLE_MARK_X1 (MIDDLE_MARK_X2 - MIDDLE_MARK_LENGTH) #define LITTLE_MARK_LENGTH (MIDDLE_MARK_LENGTH / 2) #define LITTLE_MARK_X2 LINE_END #define LITTLE_MARK_X1 (LITTLE_MARK_X2 - LITTLE_MARK_LENGTH) #define BASE_MARK_LENGTH (LITTLE_MARK_LENGTH / 2) #define BASE_MARK_X2 LINE_END #define BASE_MARK_X1 (BASE_MARK_X2 - BASE_MARK_LENGTH) #define LABEL_SIZE 8 #define END_LABEL_X 4 #define END_LABEL_Y (END_LABEL_X + LABEL_SIZE - 2) #undef PROFILING #ifdef PROFILING #include #endif class KRulerPrivate { public: int endOffset_length; /* marks the offset at the end of the ruler * i.e. right side at horizontal and down side * at vertical rulers. * the ruler end mark is moved endOffset_length * ticks away from the widget end. * positive offset moves end mark inside the ruler. * if lengthFix is true, endOffset_length holds the * length of the ruler. */ int fontWidth; // ONLY valid for vertical rulers QAbstractSlider range; Qt::Orientation dir; int tmDist; int lmDist; int mmDist; int bmDist; int offset; bool showtm : 1; /* show tiny, little, medium, big, endmarks */ bool showlm : 1; bool showmm : 1; bool showbm : 1; bool showem : 1; bool showpointer : 1; bool showEndL : 1; bool lengthFix : 1; double ppm; /* pixel per mark */ QString endlabel; }; KRuler::KRuler(QWidget *parent) : QAbstractSlider(parent) , d(new KRulerPrivate) { setRange(INIT_MIN_VALUE, INIT_MAX_VALUE); setPageStep(10); setValue(INIT_VALUE); initWidget(Qt::Horizontal); setFixedHeight(FIX_WIDTH); } KRuler::KRuler(Qt::Orientation orient, QWidget *parent, Qt::WindowFlags f) : QAbstractSlider(parent) , d(new KRulerPrivate) { setRange(INIT_MIN_VALUE, INIT_MAX_VALUE); setPageStep(10); setValue(INIT_VALUE); setWindowFlags(f); initWidget(orient); if (orient == Qt::Horizontal) { setFixedHeight(FIX_WIDTH); } else { setFixedWidth(FIX_WIDTH); } } KRuler::KRuler(Qt::Orientation orient, int widgetWidth, QWidget *parent, Qt::WindowFlags f) : QAbstractSlider(parent) , d(new KRulerPrivate) { setRange(INIT_MIN_VALUE, INIT_MAX_VALUE); setPageStep(10); setValue(INIT_VALUE); setWindowFlags(f); initWidget(orient); if (orient == Qt::Horizontal) { setFixedHeight(widgetWidth); } else { setFixedWidth(widgetWidth); } } void KRuler::initWidget(Qt::Orientation orientation) { d->showpointer = INIT_SHOW_POINTER; d->showEndL = INIT_SHOW_END_LABEL; d->lengthFix = INIT_LENGTH_FIX; d->endOffset_length = INIT_END_OFFSET; d->tmDist = INIT_TINY_MARK_DISTANCE; d->lmDist = INIT_LITTLE_MARK_DISTANCE; d->mmDist = INIT_MIDDLE_MARK_DISTANCE; d->bmDist = INIT_BIG_MARK_DISTANCE; d->offset = INIT_OFFSET; d->showtm = INIT_SHOW_TINY_MARK; d->showlm = INIT_SHOW_LITTLE_MARK; d->showmm = INIT_SHOW_MEDIUM_MARK; d->showbm = INIT_SHOW_BIG_MARK; d->showem = INIT_SHOW_END_MARK; d->ppm = INIT_PIXEL_PER_MARK; d->dir = orientation; } KRuler::~KRuler() = default; void KRuler::setTinyMarkDistance(int dist) { if (dist != d->tmDist) { d->tmDist = dist; update(contentsRect()); } } int KRuler::tinyMarkDistance() const { return d->tmDist; } void KRuler::setLittleMarkDistance(int dist) { if (dist != d->lmDist) { d->lmDist = dist; update(contentsRect()); } } int KRuler::littleMarkDistance() const { return d->lmDist; } void KRuler::setMediumMarkDistance(int dist) { if (dist != d->mmDist) { d->mmDist = dist; update(contentsRect()); } } int KRuler::mediumMarkDistance() const { return d->mmDist; } void KRuler::setBigMarkDistance(int dist) { if (dist != d->bmDist) { d->bmDist = dist; update(contentsRect()); } } int KRuler::bigMarkDistance() const { return d->bmDist; } void KRuler::setShowTinyMarks(bool show) { if (show != d->showtm) { d->showtm = show; update(contentsRect()); } } bool KRuler::showTinyMarks() const { return d->showtm; } void KRuler::setShowLittleMarks(bool show) { if (show != d->showlm) { d->showlm = show; update(contentsRect()); } } bool KRuler::showLittleMarks() const { return d->showlm; } void KRuler::setShowMediumMarks(bool show) { if (show != d->showmm) { d->showmm = show; update(contentsRect()); } } bool KRuler::showMediumMarks() const { return d->showmm; } void KRuler::setShowBigMarks(bool show) { if (show != d->showbm) { d->showbm = show; update(contentsRect()); } } bool KRuler::showBigMarks() const { return d->showbm; } void KRuler::setShowEndMarks(bool show) { if (show != d->showem) { d->showem = show; update(contentsRect()); } } bool KRuler::showEndMarks() const { return d->showem; } void KRuler::setShowPointer(bool show) { if (show != d->showpointer) { d->showpointer = show; update(contentsRect()); } } bool KRuler::showPointer() const { return d->showpointer; } void KRuler::setShowEndLabel(bool show) { if (d->showEndL != show) { d->showEndL = show; update(contentsRect()); } } bool KRuler::showEndLabel() const { return d->showEndL; } void KRuler::setEndLabel(const QString &label) { d->endlabel = label; // premeasure the fontwidth and save it if (d->dir == Qt::Vertical) { QFont font = this->font(); font.setPointSize(LABEL_SIZE); QFontMetrics fm(font); d->fontWidth = fm.horizontalAdvance(d->endlabel); } update(contentsRect()); } QString KRuler::endLabel() const { return d->endlabel; } void KRuler::setRulerMetricStyle(KRuler::MetricStyle style) { switch (style) { default: /* fall through */ case Custom: return; case Pixel: setLittleMarkDistance(1); setMediumMarkDistance(5); setBigMarkDistance(10); setShowTinyMarks(false); setShowLittleMarks(true); setShowMediumMarks(true); setShowBigMarks(true); setShowEndMarks(true); update(contentsRect()); setPixelPerMark(10.0); break; case Inch: setTinyMarkDistance(1); setLittleMarkDistance(2); setMediumMarkDistance(4); setBigMarkDistance(8); setShowTinyMarks(true); setShowLittleMarks(true); setShowMediumMarks(true); setShowBigMarks(true); setShowEndMarks(true); update(contentsRect()); setPixelPerMark(9.0); break; case Millimetres: /* fall through */ case Centimetres: /* fall through */ case Metres: setLittleMarkDistance(1); setMediumMarkDistance(5); setBigMarkDistance(10); setShowTinyMarks(false); setShowLittleMarks(true); setShowMediumMarks(true); setShowBigMarks(true); setShowEndMarks(true); update(contentsRect()); setPixelPerMark(3.0); } switch (style) { case Pixel: setEndLabel(QStringLiteral("pixel")); break; case Inch: setEndLabel(QStringLiteral("inch")); break; case Millimetres: setEndLabel(QStringLiteral("mm")); break; case Centimetres: setEndLabel(QStringLiteral("cm")); break; case Metres: setEndLabel(QStringLiteral("m")); default: /* never reached, see above switch */ /* empty command */; } // if the style changes one of the values, // update would have been called inside the methods // -> no update() call needed here ! } void KRuler::setPixelPerMark(double rate) { // never compare floats against each other :) d->ppm = rate; update(contentsRect()); } double KRuler::pixelPerMark() const { return d->ppm; } void KRuler::setLength(int length) { int tmp; if (d->lengthFix) { tmp = length; } else { tmp = width() - length; } if (tmp != d->endOffset_length) { d->endOffset_length = tmp; update(contentsRect()); } } int KRuler::length() const { if (d->lengthFix) { return d->endOffset_length; } return (width() - d->endOffset_length); } void KRuler::setLengthFixed(bool fix) { d->lengthFix = fix; } bool KRuler::lengthFixed() const { return d->lengthFix; } void KRuler::setOffset(int _offset) { // debug("set offset %i", _offset); if (d->offset != _offset) { d->offset = _offset; update(contentsRect()); } } int KRuler::offset() const { return d->offset; } int KRuler::endOffset() const { if (d->lengthFix) { return (width() - d->endOffset_length); } return d->endOffset_length; } void KRuler::slideUp(int count) { if (count) { d->offset += count; update(contentsRect()); } } void KRuler::slideDown(int count) { if (count) { d->offset -= count; update(contentsRect()); } } void KRuler::slotNewValue(int _value) { int oldvalue = value(); if (oldvalue == _value) { return; } // setValue(_value); setValue(_value); if (value() == oldvalue) { return; } // get the rectangular of the old and the new ruler pointer // and repaint only him if (d->dir == Qt::Horizontal) { QRect oldrec(-5 + oldvalue, 10, 11, 6); QRect newrec(-5 + _value, 10, 11, 6); repaint(oldrec.united(newrec)); } else { QRect oldrec(10, -5 + oldvalue, 6, 11); QRect newrec(10, -5 + _value, 6, 11); repaint(oldrec.united(newrec)); } } void KRuler::slotNewOffset(int _offset) { if (d->offset != _offset) { // setOffset(_offset); d->offset = _offset; repaint(contentsRect()); } } void KRuler::slotEndOffset(int offset) { int tmp; if (d->lengthFix) { tmp = width() - offset; } else { tmp = offset; } if (d->endOffset_length != tmp) { d->endOffset_length = tmp; repaint(contentsRect()); } } void KRuler::paintEvent(QPaintEvent * /*e*/) { // debug ("KRuler::drawContents, %s",(horizontal==dir)?"horizontal":"vertical"); QStylePainter p(this); #ifdef PROFILING QTime time; time.start(); for (int profile = 0; profile < 10; profile++) { #endif int value = this->value(); int minval = minimum(); int maxval; if (d->dir == Qt::Horizontal) { maxval = maximum() + d->offset - (d->lengthFix ? (height() - d->endOffset_length) : d->endOffset_length); } else { maxval = maximum() + d->offset - (d->lengthFix ? (width() - d->endOffset_length) : d->endOffset_length); } // ioffsetval = value-offset; // pixelpm = (int)ppm; // left = clip.left(), // right = clip.right(); double f; double fend; double offsetmin = (double)(minval - d->offset); double offsetmax = (double)(maxval - d->offset); double fontOffset = (((double)minval) > offsetmin) ? (double)minval : offsetmin; // draw labels QFont font = p.font(); font.setPointSize(LABEL_SIZE); p.setFont(font); // draw littlemarklabel // draw mediummarklabel // draw bigmarklabel // draw endlabel if (d->showEndL) { if (d->dir == Qt::Horizontal) { p.translate(fontOffset, 0); p.drawText(END_LABEL_X, END_LABEL_Y, d->endlabel); } else { // rotate text +pi/2 and move down a bit // QFontMetrics fm(font); #ifdef KRULER_ROTATE_TEST p.rotate(-90.0 + rotate); p.translate(-8.0 - fontOffset - d->fontWidth + xtrans, ytrans); #else p.rotate(-90.0); p.translate(-8.0 - fontOffset - d->fontWidth, 0.0); #endif p.drawText(END_LABEL_X, END_LABEL_Y, d->endlabel); } p.resetTransform(); } // draw the tiny marks if (d->showtm) { fend = d->ppm * d->tmDist; for (f = offsetmin; f < offsetmax; f += fend) { if (d->dir == Qt::Horizontal) { p.drawLine((int)f, BASE_MARK_X1, (int)f, BASE_MARK_X2); } else { p.drawLine(BASE_MARK_X1, (int)f, BASE_MARK_X2, (int)f); } } } if (d->showlm) { // draw the little marks fend = d->ppm * d->lmDist; for (f = offsetmin; f < offsetmax; f += fend) { if (d->dir == Qt::Horizontal) { p.drawLine((int)f, LITTLE_MARK_X1, (int)f, LITTLE_MARK_X2); } else { p.drawLine(LITTLE_MARK_X1, (int)f, LITTLE_MARK_X2, (int)f); } } } if (d->showmm) { // draw medium marks fend = d->ppm * d->mmDist; for (f = offsetmin; f < offsetmax; f += fend) { if (d->dir == Qt::Horizontal) { p.drawLine((int)f, MIDDLE_MARK_X1, (int)f, MIDDLE_MARK_X2); } else { p.drawLine(MIDDLE_MARK_X1, (int)f, MIDDLE_MARK_X2, (int)f); } } } if (d->showbm) { // draw big marks fend = d->ppm * d->bmDist; for (f = offsetmin; f < offsetmax; f += fend) { if (d->dir == Qt::Horizontal) { p.drawLine((int)f, BIG_MARK_X1, (int)f, BIG_MARK_X2); } else { p.drawLine(BIG_MARK_X1, (int)f, BIG_MARK_X2, (int)f); } } } if (d->showem) { // draw end marks if (d->dir == Qt::Horizontal) { p.drawLine(minval - d->offset, END_MARK_X1, minval - d->offset, END_MARK_X2); p.drawLine(maxval - d->offset, END_MARK_X1, maxval - d->offset, END_MARK_X2); } else { p.drawLine(END_MARK_X1, minval - d->offset, END_MARK_X2, minval - d->offset); p.drawLine(END_MARK_X1, maxval - d->offset, END_MARK_X2, maxval - d->offset); } } // draw pointer if (d->showpointer) { QPolygon pa(4); if (d->dir == Qt::Horizontal) { pa.setPoints(3, value - 5, 10, value + 5, 10, value /*+0*/, 15); } else { pa.setPoints(3, 10, value - 5, 10, value + 5, 15, value /*+0*/); } p.setBrush(p.background().color()); p.drawPolygon(pa); } #ifdef PROFILING } int elapsed = time.elapsed(); debug("paint time %i", elapsed); #endif } #include "moc_kruler.cpp"