qwt_dial.cpp 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  1. /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
  2. * Qwt Widget Library
  3. * Copyright (C) 1997 Josef Wilgen
  4. * Copyright (C) 2002 Uwe Rathmann
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the Qwt License, Version 1.0
  8. *****************************************************************************/
  9. #include "qwt_dial.h"
  10. #include "qwt_dial_needle.h"
  11. #include "qwt_math.h"
  12. #include "qwt_scale_engine.h"
  13. #include "qwt_scale_map.h"
  14. #include "qwt_painter.h"
  15. #include <qpainter.h>
  16. #include <qbitmap.h>
  17. #include <qpalette.h>
  18. #include <qpixmap.h>
  19. #include <qevent.h>
  20. #include <qalgorithms.h>
  21. #include <qmath.h>
  22. #if QT_VERSION < 0x040601
  23. #define qAtan(x) ::atan(x)
  24. #endif
  25. class QwtDial::PrivateData
  26. {
  27. public:
  28. PrivateData():
  29. visibleBackground( true ),
  30. frameShadow( Sunken ),
  31. lineWidth( 0 ),
  32. mode( RotateNeedle ),
  33. direction( Clockwise ),
  34. origin( 90.0 ),
  35. minScaleArc( 0.0 ),
  36. maxScaleArc( 0.0 ),
  37. scaleDraw( 0 ),
  38. maxMajIntv( 36 ),
  39. maxMinIntv( 10 ),
  40. scaleStep( 0.0 ),
  41. needle( 0 )
  42. {
  43. }
  44. ~PrivateData()
  45. {
  46. delete scaleDraw;
  47. delete needle;
  48. }
  49. bool visibleBackground;
  50. Shadow frameShadow;
  51. int lineWidth;
  52. QwtDial::Mode mode;
  53. QwtDial::Direction direction;
  54. double origin;
  55. double minScaleArc;
  56. double maxScaleArc;
  57. QwtDialScaleDraw *scaleDraw;
  58. int maxMajIntv;
  59. int maxMinIntv;
  60. double scaleStep;
  61. QwtDialNeedle *needle;
  62. static double previousDir;
  63. };
  64. double QwtDial::PrivateData::previousDir = -1.0;
  65. /*!
  66. Constructor
  67. \param parent Parent dial widget
  68. */
  69. QwtDialScaleDraw::QwtDialScaleDraw( QwtDial *parent ):
  70. d_parent( parent ),
  71. d_penWidth( 1.0 )
  72. {
  73. }
  74. /*!
  75. Set the pen width used for painting the scale
  76. \param penWidth Pen width
  77. \sa penWidth(), QwtDial::drawScale()
  78. */
  79. void QwtDialScaleDraw::setPenWidth( double penWidth )
  80. {
  81. d_penWidth = qMax( penWidth, 0.0 );
  82. }
  83. /*!
  84. \return Pen width used for painting the scale
  85. \sa setPenWidth, QwtDial::drawScale()
  86. */
  87. double QwtDialScaleDraw::penWidth() const
  88. {
  89. return d_penWidth;
  90. }
  91. /*!
  92. Call QwtDial::scaleLabel of the parent dial widget.
  93. \param value Value to display
  94. \sa QwtDial::scaleLabel()
  95. */
  96. QwtText QwtDialScaleDraw::label( double value ) const
  97. {
  98. if ( d_parent == NULL )
  99. return QwtRoundScaleDraw::label( value );
  100. return d_parent->scaleLabel( value );
  101. }
  102. /*!
  103. \brief Constructor
  104. \param parent Parent widget
  105. Create a dial widget with no scale and no needle.
  106. The default origin is 90.0 with no valid value. It accepts
  107. mouse and keyboard inputs and has no step size. The default mode
  108. is QwtDial::RotateNeedle.
  109. */
  110. QwtDial::QwtDial( QWidget* parent ):
  111. QwtAbstractSlider( Qt::Horizontal, parent )
  112. {
  113. initDial();
  114. }
  115. void QwtDial::initDial()
  116. {
  117. d_data = new PrivateData;
  118. setFocusPolicy( Qt::TabFocus );
  119. QPalette p = palette();
  120. for ( int i = 0; i < QPalette::NColorGroups; i++ )
  121. {
  122. const QPalette::ColorGroup cg = ( QPalette::ColorGroup )i;
  123. // Base: background color of the circle inside the frame.
  124. // WindowText: background color of the circle inside the scale
  125. p.setColor( cg, QPalette::WindowText,
  126. p.color( cg, QPalette::Base ) );
  127. }
  128. setPalette( p );
  129. d_data->scaleDraw = new QwtDialScaleDraw( this );
  130. d_data->scaleDraw->setRadius( 0 );
  131. setScaleArc( 0.0, 360.0 ); // scale as a full circle
  132. setRange( 0.0, 360.0, 1.0, 10 ); // degrees as deafult
  133. }
  134. //! Destructor
  135. QwtDial::~QwtDial()
  136. {
  137. delete d_data;
  138. }
  139. /*!
  140. Show/Hide the area outside of the frame
  141. \param show Show if true, hide if false
  142. \sa hasVisibleBackground(), setMask()
  143. \warning When QwtDial is a toplevel widget the window
  144. border might disappear too.
  145. */
  146. void QwtDial::showBackground( bool show )
  147. {
  148. if ( d_data->visibleBackground != show )
  149. {
  150. d_data->visibleBackground = show;
  151. updateMask();
  152. }
  153. }
  154. /*!
  155. true when the area outside of the frame is visible
  156. \sa showBackground(), setMask()
  157. */
  158. bool QwtDial::hasVisibleBackground() const
  159. {
  160. return d_data->visibleBackground;
  161. }
  162. /*!
  163. Sets the frame shadow value from the frame style.
  164. \param shadow Frame shadow
  165. \sa setLineWidth(), QFrame::setFrameShadow()
  166. */
  167. void QwtDial::setFrameShadow( Shadow shadow )
  168. {
  169. if ( shadow != d_data->frameShadow )
  170. {
  171. d_data->frameShadow = shadow;
  172. if ( lineWidth() > 0 )
  173. update();
  174. }
  175. }
  176. /*!
  177. \return Frame shadow
  178. /sa setFrameShadow(), lineWidth(), QFrame::frameShadow
  179. */
  180. QwtDial::Shadow QwtDial::frameShadow() const
  181. {
  182. return d_data->frameShadow;
  183. }
  184. /*!
  185. Sets the line width
  186. \param lineWidth Line width
  187. \sa setFrameShadow()
  188. */
  189. void QwtDial::setLineWidth( int lineWidth )
  190. {
  191. if ( lineWidth < 0 )
  192. lineWidth = 0;
  193. if ( d_data->lineWidth != lineWidth )
  194. {
  195. d_data->lineWidth = lineWidth;
  196. update();
  197. }
  198. }
  199. /*!
  200. \return Line width of the frame
  201. \sa setLineWidth(), frameShadow(), lineWidth()
  202. */
  203. int QwtDial::lineWidth() const
  204. {
  205. return d_data->lineWidth;
  206. }
  207. /*!
  208. \return bounding rect of the circle inside the frame
  209. \sa setLineWidth(), scaleContentsRect(), boundingRect()
  210. */
  211. QRect QwtDial::contentsRect() const
  212. {
  213. const int lw = lineWidth();
  214. QRect r = boundingRect();
  215. if ( lw > 0 )
  216. {
  217. r.setRect( r.x() + lw, r.y() + lw,
  218. r.width() - 2 * lw, r.height() - 2 * lw );
  219. }
  220. return r;
  221. }
  222. /*!
  223. \return bounding rect of the dial including the frame
  224. \sa setLineWidth(), scaleContentsRect(), contentsRect()
  225. */
  226. QRect QwtDial::boundingRect() const
  227. {
  228. const int radius = qMin( width(), height() ) / 2;
  229. QRect r( 0, 0, 2 * radius, 2 * radius );
  230. r.moveCenter( rect().center() );
  231. return r;
  232. }
  233. /*!
  234. \return rect inside the scale
  235. \sa setLineWidth(), boundingRect(), contentsRect()
  236. */
  237. QRect QwtDial::scaleContentsRect() const
  238. {
  239. const QPen scalePen( palette().text(), 0, Qt::NoPen );
  240. int scaleDist = 0;
  241. if ( d_data->scaleDraw )
  242. {
  243. scaleDist = qCeil( d_data->scaleDraw->extent( font() ) );
  244. scaleDist++; // margin
  245. }
  246. const QRect rect = contentsRect();
  247. return QRect( rect.x() + scaleDist, rect.y() + scaleDist,
  248. rect.width() - 2 * scaleDist, rect.height() - 2 * scaleDist );
  249. }
  250. /*!
  251. \brief Change the mode of the meter.
  252. \param mode New mode
  253. The value of the meter is indicated by the difference
  254. between north of the scale and the direction of the needle.
  255. In case of QwtDial::RotateNeedle north is pointing
  256. to the origin() and the needle is rotating, in case of
  257. QwtDial::RotateScale, the needle points to origin()
  258. and the scale is rotating.
  259. The default mode is QwtDial::RotateNeedle.
  260. \sa mode(), setValue(), setOrigin()
  261. */
  262. void QwtDial::setMode( Mode mode )
  263. {
  264. if ( mode != d_data->mode )
  265. {
  266. d_data->mode = mode;
  267. update();
  268. }
  269. }
  270. /*!
  271. \return mode of the dial.
  272. The value of the dial is indicated by the difference
  273. between the origin and the direction of the needle.
  274. In case of QwtDial::RotateNeedle the scale arc is fixed
  275. to the origin() and the needle is rotating, in case of
  276. QwtDial::RotateScale, the needle points to origin()
  277. and the scale is rotating.
  278. The default mode is QwtDial::RotateNeedle.
  279. \sa setMode(), origin(), setScaleArc(), value()
  280. */
  281. QwtDial::Mode QwtDial::mode() const
  282. {
  283. return d_data->mode;
  284. }
  285. /*!
  286. Sets whether it is possible to step the value from the highest value to
  287. the lowest value and vice versa to on.
  288. \param wrapping en/disables wrapping
  289. \sa wrapping(), QwtDoubleRange::periodic()
  290. \note The meaning of wrapping is like the wrapping property of QSpinBox,
  291. but not like it is used in QDial.
  292. */
  293. void QwtDial::setWrapping( bool wrapping )
  294. {
  295. setPeriodic( wrapping );
  296. }
  297. /*!
  298. wrapping() holds whether it is possible to step the value from the
  299. highest value to the lowest value and vice versa.
  300. \sa setWrapping(), QwtDoubleRange::setPeriodic()
  301. \note The meaning of wrapping is like the wrapping property of QSpinBox,
  302. but not like it is used in QDial.
  303. */
  304. bool QwtDial::wrapping() const
  305. {
  306. return periodic();
  307. }
  308. /*!
  309. Set the direction of the dial (clockwise/counterclockwise)
  310. Direction direction
  311. \sa direction()
  312. */
  313. void QwtDial::setDirection( Direction direction )
  314. {
  315. if ( direction != d_data->direction )
  316. {
  317. d_data->direction = direction;
  318. update();
  319. }
  320. }
  321. /*!
  322. \return Direction of the dial
  323. The default direction of a dial is QwtDial::Clockwise
  324. \sa setDirection()
  325. */
  326. QwtDial::Direction QwtDial::direction() const
  327. {
  328. return d_data->direction;
  329. }
  330. /*!
  331. Resize the dial widget
  332. \param e Resize event
  333. */
  334. void QwtDial::resizeEvent( QResizeEvent *e )
  335. {
  336. QWidget::resizeEvent( e );
  337. if ( !hasVisibleBackground() )
  338. updateMask();
  339. }
  340. /*!
  341. Paint the dial
  342. \param e Paint event
  343. */
  344. void QwtDial::paintEvent( QPaintEvent *e )
  345. {
  346. const QRect &ur = e->rect();
  347. if ( ur.isValid() )
  348. {
  349. QPainter painter( this );
  350. painter.setRenderHint( QPainter::Antialiasing, true );
  351. painter.save();
  352. drawContents( &painter );
  353. painter.restore();
  354. painter.save();
  355. drawFrame( &painter );
  356. painter.restore();
  357. if ( hasFocus() )
  358. drawFocusIndicator( &painter );
  359. }
  360. }
  361. /*!
  362. Draw a dotted round circle, if !isReadOnly()
  363. \param painter Painter
  364. */
  365. void QwtDial::drawFocusIndicator( QPainter *painter ) const
  366. {
  367. if ( !isReadOnly() )
  368. {
  369. QRect focusRect = contentsRect();
  370. const int margin = 2;
  371. focusRect.setRect(
  372. focusRect.x() + margin,
  373. focusRect.y() + margin,
  374. focusRect.width() - 2 * margin,
  375. focusRect.height() - 2 * margin );
  376. QColor color = palette().color( QPalette::Base );
  377. if ( color.isValid() )
  378. {
  379. const QColor gray( Qt::gray );
  380. int h, s, v;
  381. color.getHsv( &h, &s, &v );
  382. color = ( v > 128 ) ? gray.dark( 120 ) : gray.light( 120 );
  383. }
  384. else
  385. color = Qt::darkGray;
  386. painter->save();
  387. painter->setBrush( Qt::NoBrush );
  388. painter->setPen( QPen( color, 0, Qt::DotLine ) );
  389. painter->drawEllipse( focusRect );
  390. painter->restore();
  391. }
  392. }
  393. /*!
  394. Draw the frame around the dial
  395. \param painter Painter
  396. \sa lineWidth(), frameShadow()
  397. */
  398. void QwtDial::drawFrame( QPainter *painter )
  399. {
  400. const int lw = lineWidth();
  401. const int off = ( lw + 1 ) % 2;
  402. QRect r = boundingRect();
  403. r.setRect( r.x() + lw / 2 - off, r.y() + lw / 2 - off,
  404. r.width() - lw + off + 1, r.height() - lw + off + 1 );
  405. r.setX( r.x() + 1 );
  406. r.setY( r.y() + 1 );
  407. r.setWidth( r.width() - 2 );
  408. r.setHeight( r.height() - 2 );
  409. if ( lw > 0 )
  410. {
  411. switch ( d_data->frameShadow )
  412. {
  413. case QwtDial::Raised:
  414. QwtPainter::drawRoundFrame( painter, r,
  415. lw, palette(), false );
  416. break;
  417. case QwtDial::Sunken:
  418. QwtPainter::drawRoundFrame( painter, r,
  419. lw, palette(), true );
  420. break;
  421. default: // Plain
  422. {
  423. painter->save();
  424. painter->setPen( QPen( Qt::black, lw ) );
  425. painter->setBrush( Qt::NoBrush );
  426. painter->drawEllipse( r );
  427. painter->restore();
  428. }
  429. }
  430. }
  431. }
  432. /*!
  433. \brief Draw the contents inside the frame
  434. QPalette::Window is the background color outside of the frame.
  435. QPalette::Base is the background color inside the frame.
  436. QPalette::WindowText is the background color inside the scale.
  437. \param painter Painter
  438. \sa boundingRect(), contentsRect(),
  439. scaleContentsRect(), QWidget::setPalette()
  440. */
  441. void QwtDial::drawContents( QPainter *painter ) const
  442. {
  443. if ( testAttribute( Qt::WA_NoSystemBackground ) ||
  444. palette().brush( QPalette::Base ) !=
  445. palette().brush( QPalette::Window ) )
  446. {
  447. const QRect br = boundingRect();
  448. painter->save();
  449. painter->setPen( Qt::NoPen );
  450. painter->setBrush( palette().brush( QPalette::Base ) );
  451. painter->drawEllipse( br );
  452. painter->restore();
  453. }
  454. const QRect insideScaleRect = scaleContentsRect();
  455. if ( palette().brush( QPalette::WindowText ) !=
  456. palette().brush( QPalette::Base ) )
  457. {
  458. painter->save();
  459. painter->setPen( Qt::NoPen );
  460. painter->setBrush( palette().brush( QPalette::WindowText ) );
  461. painter->drawEllipse( insideScaleRect.x() - 1, insideScaleRect.y() - 1,
  462. insideScaleRect.width(), insideScaleRect.height() );
  463. painter->restore();
  464. }
  465. const QPoint center = insideScaleRect.center();
  466. const int radius = insideScaleRect.width() / 2;
  467. painter->save();
  468. drawScaleContents( painter, center, radius );
  469. painter->restore();
  470. double direction = d_data->origin;
  471. if ( isValid() )
  472. {
  473. direction = d_data->minScaleArc;
  474. if ( maxValue() > minValue() && d_data->maxScaleArc > d_data->minScaleArc )
  475. {
  476. const double ratio =
  477. ( value() - minValue() ) / ( maxValue() - minValue() );
  478. direction += ratio * ( d_data->maxScaleArc - d_data->minScaleArc );
  479. }
  480. if ( d_data->direction == QwtDial::CounterClockwise )
  481. direction = d_data->maxScaleArc - ( direction - d_data->minScaleArc );
  482. direction += d_data->origin;
  483. if ( direction >= 360.0 )
  484. direction -= 360.0;
  485. else if ( direction < 0.0 )
  486. direction += 360.0;
  487. }
  488. double origin = d_data->origin;
  489. if ( mode() == RotateScale )
  490. {
  491. origin -= direction - d_data->origin;
  492. direction = d_data->origin;
  493. }
  494. painter->save();
  495. drawScale( painter, center, radius, origin,
  496. d_data->minScaleArc, d_data->maxScaleArc );
  497. painter->restore();
  498. if ( isValid() )
  499. {
  500. QPalette::ColorGroup cg;
  501. if ( isEnabled() )
  502. cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
  503. else
  504. cg = QPalette::Disabled;
  505. painter->save();
  506. drawNeedle( painter, center, radius, direction, cg );
  507. painter->restore();
  508. }
  509. }
  510. /*!
  511. Draw the needle
  512. \param painter Painter
  513. \param center Center of the dial
  514. \param radius Length for the needle
  515. \param direction Direction of the needle in degrees, counter clockwise
  516. \param cg ColorGroup
  517. */
  518. void QwtDial::drawNeedle( QPainter *painter, const QPoint &center,
  519. int radius, double direction, QPalette::ColorGroup cg ) const
  520. {
  521. if ( d_data->needle )
  522. {
  523. direction = 360.0 - direction; // counter clockwise
  524. d_data->needle->draw( painter, center, radius, direction, cg );
  525. }
  526. }
  527. /*!
  528. Draw the scale
  529. \param painter Painter
  530. \param center Center of the dial
  531. \param radius Radius of the scale
  532. \param origin Origin of the scale
  533. \param minArc Minimum of the arc
  534. \param maxArc Minimum of the arc
  535. \sa QwtAbstractScaleDraw::setAngleRange()
  536. */
  537. void QwtDial::drawScale( QPainter *painter, const QPoint &center,
  538. int radius, double origin, double minArc, double maxArc ) const
  539. {
  540. if ( d_data->scaleDraw == NULL )
  541. return;
  542. origin -= 270.0; // hardcoded origin of QwtScaleDraw
  543. double angle = maxArc - minArc;
  544. if ( angle > 360.0 )
  545. angle = ::fmod( angle, 360.0 );
  546. minArc += origin;
  547. if ( minArc < -360.0 )
  548. minArc = ::fmod( minArc, 360.0 );
  549. maxArc = minArc + angle;
  550. if ( maxArc > 360.0 )
  551. {
  552. // QwtAbstractScaleDraw::setAngleRange accepts only values
  553. // in the range [-360.0..360.0]
  554. minArc -= 360.0;
  555. maxArc -= 360.0;
  556. }
  557. if ( d_data->direction == QwtDial::CounterClockwise )
  558. qSwap( minArc, maxArc );
  559. painter->setFont( font() );
  560. d_data->scaleDraw->setAngleRange( minArc, maxArc );
  561. d_data->scaleDraw->setRadius( radius );
  562. d_data->scaleDraw->moveCenter( center );
  563. QPalette pal = palette();
  564. const QColor textColor = pal.color( QPalette::Text );
  565. pal.setColor( QPalette::WindowText, textColor ); //ticks, backbone
  566. painter->setPen( QPen( textColor, d_data->scaleDraw->penWidth() ) );
  567. d_data->scaleDraw->draw( painter, pal );
  568. }
  569. void QwtDial::drawScaleContents( QPainter *,
  570. const QPoint &, int ) const
  571. {
  572. // empty default implementation
  573. }
  574. /*!
  575. Set a needle for the dial
  576. Qwt is missing a set of good looking needles.
  577. Contributions are very welcome.
  578. \param needle Needle
  579. \warning The needle will be deleted, when a different needle is
  580. set or in ~QwtDial()
  581. */
  582. void QwtDial::setNeedle( QwtDialNeedle *needle )
  583. {
  584. if ( needle != d_data->needle )
  585. {
  586. if ( d_data->needle )
  587. delete d_data->needle;
  588. d_data->needle = needle;
  589. update();
  590. }
  591. }
  592. /*!
  593. \return needle
  594. \sa setNeedle()
  595. */
  596. const QwtDialNeedle *QwtDial::needle() const
  597. {
  598. return d_data->needle;
  599. }
  600. /*!
  601. \return needle
  602. \sa setNeedle()
  603. */
  604. QwtDialNeedle *QwtDial::needle()
  605. {
  606. return d_data->needle;
  607. }
  608. //! QwtDoubleRange update hook
  609. void QwtDial::rangeChange()
  610. {
  611. updateScale();
  612. }
  613. /*!
  614. Update the scale with the current attributes
  615. \sa setScale()
  616. */
  617. void QwtDial::updateScale()
  618. {
  619. if ( d_data->scaleDraw )
  620. {
  621. QwtLinearScaleEngine scaleEngine;
  622. const QwtScaleDiv scaleDiv = scaleEngine.divideScale(
  623. minValue(), maxValue(),
  624. d_data->maxMajIntv, d_data->maxMinIntv, d_data->scaleStep );
  625. d_data->scaleDraw->setTransformation( scaleEngine.transformation() );
  626. d_data->scaleDraw->setScaleDiv( scaleDiv );
  627. }
  628. }
  629. //! Return the scale draw
  630. QwtDialScaleDraw *QwtDial::scaleDraw()
  631. {
  632. return d_data->scaleDraw;
  633. }
  634. //! Return the scale draw
  635. const QwtDialScaleDraw *QwtDial::scaleDraw() const
  636. {
  637. return d_data->scaleDraw;
  638. }
  639. /*!
  640. Set an individual scale draw
  641. \param scaleDraw Scale draw
  642. \warning The previous scale draw is deleted
  643. */
  644. void QwtDial::setScaleDraw( QwtDialScaleDraw *scaleDraw )
  645. {
  646. if ( scaleDraw != d_data->scaleDraw )
  647. {
  648. if ( d_data->scaleDraw )
  649. delete d_data->scaleDraw;
  650. d_data->scaleDraw = scaleDraw;
  651. updateScale();
  652. update();
  653. }
  654. }
  655. /*!
  656. Change the intervals of the scale
  657. \sa QwtAbstractScaleDraw::setScale()
  658. */
  659. void QwtDial::setScale( int maxMajIntv, int maxMinIntv, double step )
  660. {
  661. d_data->maxMajIntv = maxMajIntv;
  662. d_data->maxMinIntv = maxMinIntv;
  663. d_data->scaleStep = step;
  664. updateScale();
  665. }
  666. /*!
  667. A wrapper method for accessing the scale draw.
  668. - options == 0\n
  669. No visible scale: setScaleDraw(NULL)
  670. - options & ScaleBackbone\n
  671. En/disable the backbone of the scale.
  672. - options & ScaleTicks\n
  673. En/disable the ticks of the scale.
  674. - options & ScaleLabel\n
  675. En/disable scale labels
  676. \sa QwtAbstractScaleDraw::enableComponent()
  677. */
  678. void QwtDial::setScaleOptions( int options )
  679. {
  680. if ( options == 0 )
  681. setScaleDraw( NULL );
  682. QwtDialScaleDraw *sd = d_data->scaleDraw;
  683. if ( sd == NULL )
  684. return;
  685. sd->enableComponent( QwtAbstractScaleDraw::Backbone,
  686. options & ScaleBackbone );
  687. sd->enableComponent( QwtAbstractScaleDraw::Ticks,
  688. options & ScaleTicks );
  689. sd->enableComponent( QwtAbstractScaleDraw::Labels,
  690. options & ScaleLabel );
  691. }
  692. /*!
  693. Assign length and width of the ticks
  694. \param minLen Length of the minor ticks
  695. \param medLen Length of the medium ticks
  696. \param majLen Length of the major ticks
  697. \param penWidth Width of the pen for all ticks
  698. \sa QwtAbstractScaleDraw::setTickLength(), QwtDialScaleDraw::setPenWidth()
  699. */
  700. void QwtDial::setScaleTicks( int minLen, int medLen,
  701. int majLen, int penWidth )
  702. {
  703. QwtDialScaleDraw *sd = d_data->scaleDraw;
  704. if ( sd )
  705. {
  706. sd->setTickLength( QwtScaleDiv::MinorTick, minLen );
  707. sd->setTickLength( QwtScaleDiv::MediumTick, medLen );
  708. sd->setTickLength( QwtScaleDiv::MajorTick, majLen );
  709. sd->setPenWidth( penWidth );
  710. }
  711. }
  712. /*!
  713. Find the label for a value
  714. \param value Value
  715. \return label
  716. */
  717. QwtText QwtDial::scaleLabel( double value ) const
  718. {
  719. #if 1
  720. if ( value == -0 )
  721. value = 0;
  722. #endif
  723. return QString::number( value );
  724. }
  725. //! \return Lower limit of the scale arc
  726. double QwtDial::minScaleArc() const
  727. {
  728. return d_data->minScaleArc;
  729. }
  730. //! \return Upper limit of the scale arc
  731. double QwtDial::maxScaleArc() const
  732. {
  733. return d_data->maxScaleArc;
  734. }
  735. /*!
  736. \brief Change the origin
  737. The origin is the angle where scale and needle is relative to.
  738. \param origin New origin
  739. \sa origin()
  740. */
  741. void QwtDial::setOrigin( double origin )
  742. {
  743. d_data->origin = origin;
  744. update();
  745. }
  746. /*!
  747. The origin is the angle where scale and needle is relative to.
  748. \return Origin of the dial
  749. \sa setOrigin()
  750. */
  751. double QwtDial::origin() const
  752. {
  753. return d_data->origin;
  754. }
  755. /*!
  756. Change the arc of the scale
  757. \param minArc Lower limit
  758. \param maxArc Upper limit
  759. */
  760. void QwtDial::setScaleArc( double minArc, double maxArc )
  761. {
  762. if ( minArc != 360.0 && minArc != -360.0 )
  763. minArc = ::fmod( minArc, 360.0 );
  764. if ( maxArc != 360.0 && maxArc != -360.0 )
  765. maxArc = ::fmod( maxArc, 360.0 );
  766. d_data->minScaleArc = qMin( minArc, maxArc );
  767. d_data->maxScaleArc = qMax( minArc, maxArc );
  768. if ( d_data->maxScaleArc - d_data->minScaleArc > 360.0 )
  769. d_data->maxScaleArc = d_data->minScaleArc + 360.0;
  770. update();
  771. }
  772. //! QwtDoubleRange update hook
  773. void QwtDial::valueChange()
  774. {
  775. update();
  776. QwtAbstractSlider::valueChange();
  777. }
  778. /*!
  779. \return Size hint
  780. */
  781. QSize QwtDial::sizeHint() const
  782. {
  783. int sh = 0;
  784. if ( d_data->scaleDraw )
  785. sh = qCeil( d_data->scaleDraw->extent( font() ) );
  786. const int d = 6 * sh + 2 * lineWidth();
  787. return QSize( d, d );
  788. }
  789. /*!
  790. \brief Return a minimum size hint
  791. \warning The return value of QwtDial::minimumSizeHint() depends on the
  792. font and the scale.
  793. */
  794. QSize QwtDial::minimumSizeHint() const
  795. {
  796. int sh = 0;
  797. if ( d_data->scaleDraw )
  798. sh = qCeil( d_data->scaleDraw->extent( font() ) );
  799. const int d = 3 * sh + 2 * lineWidth();
  800. return QSize( d, d );
  801. }
  802. static double line2Radians( const QPoint &p1, const QPoint &p2 )
  803. {
  804. const QPoint p = p2 - p1;
  805. double angle;
  806. if ( p.x() == 0 )
  807. angle = ( p.y() <= 0 ) ? M_PI_2 : 3 * M_PI_2;
  808. else
  809. {
  810. angle = qAtan( double( -p.y() ) / double( p.x() ) );
  811. if ( p.x() < 0 )
  812. angle += M_PI;
  813. if ( angle < 0.0 )
  814. angle += 2 * M_PI;
  815. }
  816. return 360.0 - angle * 180.0 / M_PI;
  817. }
  818. /*!
  819. Find the value for a given position
  820. \param pos Position
  821. \return Value
  822. */
  823. double QwtDial::getValue( const QPoint &pos )
  824. {
  825. if ( d_data->maxScaleArc == d_data->minScaleArc || maxValue() == minValue() )
  826. return minValue();
  827. double dir = line2Radians( rect().center(), pos ) - d_data->origin;
  828. if ( dir < 0.0 )
  829. dir += 360.0;
  830. if ( mode() == RotateScale )
  831. dir = 360.0 - dir;
  832. // The position might be in the area that is outside the scale arc.
  833. // We need the range of the scale if it was a complete circle.
  834. const double completeCircle = 360.0 / ( d_data->maxScaleArc - d_data->minScaleArc )
  835. * ( maxValue() - minValue() );
  836. double posValue = minValue() + completeCircle * dir / 360.0;
  837. if ( scrollMode() == ScrMouse )
  838. {
  839. if ( d_data->previousDir >= 0.0 ) // valid direction
  840. {
  841. // We have to find out whether the mouse is moving
  842. // clock or counter clockwise
  843. bool clockWise = false;
  844. const double angle = dir - d_data->previousDir;
  845. if ( ( angle >= 0.0 && angle <= 180.0 ) || angle < -180.0 )
  846. clockWise = true;
  847. if ( clockWise )
  848. {
  849. if ( dir < d_data->previousDir && mouseOffset() > 0.0 )
  850. {
  851. // We passed 360 -> 0
  852. setMouseOffset( mouseOffset() - completeCircle );
  853. }
  854. if ( wrapping() )
  855. {
  856. if ( posValue - mouseOffset() > maxValue() )
  857. {
  858. // We passed maxValue and the value will be set
  859. // to minValue. We have to adjust the mouseOffset.
  860. setMouseOffset( posValue - minValue() );
  861. }
  862. }
  863. else
  864. {
  865. if ( posValue - mouseOffset() > maxValue() ||
  866. value() == maxValue() )
  867. {
  868. // We fix the value at maxValue by adjusting
  869. // the mouse offset.
  870. setMouseOffset( posValue - maxValue() );
  871. }
  872. }
  873. }
  874. else
  875. {
  876. if ( dir > d_data->previousDir && mouseOffset() < 0.0 )
  877. {
  878. // We passed 0 -> 360
  879. setMouseOffset( mouseOffset() + completeCircle );
  880. }
  881. if ( wrapping() )
  882. {
  883. if ( posValue - mouseOffset() < minValue() )
  884. {
  885. // We passed minValue and the value will be set
  886. // to maxValue. We have to adjust the mouseOffset.
  887. setMouseOffset( posValue - maxValue() );
  888. }
  889. }
  890. else
  891. {
  892. if ( posValue - mouseOffset() < minValue() ||
  893. value() == minValue() )
  894. {
  895. // We fix the value at minValue by adjusting
  896. // the mouse offset.
  897. setMouseOffset( posValue - minValue() );
  898. }
  899. }
  900. }
  901. }
  902. d_data->previousDir = dir;
  903. }
  904. return posValue;
  905. }
  906. /*!
  907. See QwtAbstractSlider::getScrollMode()
  908. \param pos point where the mouse was pressed
  909. \retval scrollMode The scrolling mode
  910. \retval direction direction: 1, 0, or -1.
  911. \sa QwtAbstractSlider::getScrollMode()
  912. */
  913. void QwtDial::getScrollMode( const QPoint &pos, int &scrollMode, int &direction )
  914. {
  915. direction = 0;
  916. scrollMode = ScrNone;
  917. const QRegion region( contentsRect(), QRegion::Ellipse );
  918. if ( region.contains( pos ) && pos != rect().center() )
  919. {
  920. scrollMode = ScrMouse;
  921. d_data->previousDir = -1.0;
  922. }
  923. }
  924. /*!
  925. Handles key events
  926. - Key_Down, KeyLeft\n
  927. Decrement by 1
  928. - Key_Prior\n
  929. Decrement by pageSize()
  930. - Key_Home\n
  931. Set the value to minValue()
  932. - Key_Up, KeyRight\n
  933. Increment by 1
  934. - Key_Next\n
  935. Increment by pageSize()
  936. - Key_End\n
  937. Set the value to maxValue()
  938. \param event Key event
  939. \sa isReadOnly()
  940. */
  941. void QwtDial::keyPressEvent( QKeyEvent *event )
  942. {
  943. if ( isReadOnly() )
  944. {
  945. event->ignore();
  946. return;
  947. }
  948. if ( !isValid() )
  949. return;
  950. double previous = prevValue();
  951. switch ( event->key() )
  952. {
  953. case Qt::Key_Down:
  954. case Qt::Key_Left:
  955. QwtDoubleRange::incValue( -1 );
  956. break;
  957. case Qt::Key_PageUp:
  958. QwtDoubleRange::incValue( -pageSize() );
  959. break;
  960. case Qt::Key_Home:
  961. setValue( minValue() );
  962. break;
  963. case Qt::Key_Up:
  964. case Qt::Key_Right:
  965. QwtDoubleRange::incValue( 1 );
  966. break;
  967. case Qt::Key_PageDown:
  968. QwtDoubleRange::incValue( pageSize() );
  969. break;
  970. case Qt::Key_End:
  971. setValue( maxValue() );
  972. break;
  973. default:;
  974. event->ignore();
  975. }
  976. if ( value() != previous )
  977. Q_EMIT sliderMoved( value() );
  978. }
  979. /*!
  980. \brief Update the mask of the dial
  981. In case of "hasVisibleBackground() == false", the backgound is
  982. transparent by a mask.
  983. \sa showBackground(), hasVisibleBackground()
  984. */
  985. void QwtDial::updateMask()
  986. {
  987. if ( d_data->visibleBackground )
  988. clearMask();
  989. else
  990. setMask( QRegion( boundingRect(), QRegion::Ellipse ) );
  991. }