ctkQImageView.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.commontk.org/LICENSE
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. #include <iostream>
  15. // CTK includes
  16. #include "ctkQImageView.h"
  17. // Qt includes
  18. #include <QApplication>
  19. #include <QLabel>
  20. #include <QHBoxLayout>
  21. #include <QDebug>
  22. #include <QResizeEvent>
  23. #include <QMouseEvent>
  24. #include <QKeyEvent>
  25. #include <QPainter>
  26. //--------------------------------------------------------------------------
  27. class ctkQImageViewPrivate
  28. {
  29. Q_DECLARE_PUBLIC( ctkQImageView );
  30. protected:
  31. ctkQImageView* const q_ptr;
  32. public:
  33. ctkQImageViewPrivate( ctkQImageView& object );
  34. void init();
  35. QLabel * Window;
  36. double Zoom;
  37. double PositionX;
  38. double PositionY;
  39. double CenterX;
  40. double CenterY;
  41. int SliceNumber;
  42. double IntensityWindowMin;
  43. double IntensityWindowMax;
  44. bool FlipXAxis;
  45. bool FlipYAxis;
  46. bool TransposeXY;
  47. QList< QImage > ImageList;
  48. QPixmap TmpImage;
  49. int TmpXMin;
  50. int TmpXMax;
  51. int TmpYMin;
  52. int TmpYMax;
  53. int MouseLastX;
  54. int MouseLastY;
  55. double MouseLastZoom;
  56. double MouseLastIntensityWindowMin;
  57. double MouseLastIntensityWindowMax;
  58. bool MouseLeftDragging;
  59. bool MouseMiddleDragging;
  60. bool MouseRightDragging;
  61. double clamp( double x, double xMin, double xMax );
  62. void fitImageRectangle( double x0, double y0, double x1, double y1 );
  63. };
  64. //--------------------------------------------------------------------------
  65. ctkQImageViewPrivate::ctkQImageViewPrivate(
  66. ctkQImageView& object )
  67. : q_ptr( &object )
  68. {
  69. this->Window = new QLabel();
  70. }
  71. //--------------------------------------------------------------------------
  72. void ctkQImageViewPrivate::init()
  73. {
  74. Q_Q( ctkQImageView );
  75. this->Window->setParent(q);
  76. QHBoxLayout* layout = new QHBoxLayout(q);
  77. layout->addWidget(this->Window);
  78. layout->setContentsMargins(0,0,0,0);
  79. q->setLayout(layout);
  80. // Set parameters for the view
  81. this->Zoom = 1;
  82. this->PositionX = 0;
  83. this->PositionY = 0;
  84. this->SliceNumber = 0;
  85. this->CenterX = 0;
  86. this->CenterY = 0;
  87. this->IntensityWindowMin = 0;
  88. this->IntensityWindowMax = 0;
  89. this->FlipXAxis = false;
  90. this->FlipYAxis = true;
  91. this->TransposeXY = false;
  92. this->ImageList.clear();
  93. this->TmpXMin = 0;
  94. this->TmpXMax = 0;
  95. this->TmpYMin = 0;
  96. this->TmpYMax = 0;
  97. this->MouseLastX = 0;
  98. this->MouseLastY = 0;
  99. this->MouseLastZoom = 0;
  100. this->MouseLeftDragging = false;
  101. this->MouseMiddleDragging = false;
  102. this->MouseRightDragging = false;
  103. // Don't expand for no reason
  104. q->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
  105. }
  106. //--------------------------------------------------------------------------
  107. double ctkQImageViewPrivate::clamp( double x, double xMin,
  108. double xMax )
  109. {
  110. if( x < xMin )
  111. {
  112. return xMin;
  113. }
  114. if( x > xMax )
  115. {
  116. return xMax;
  117. }
  118. return x;
  119. }
  120. //--------------------------------------------------------------------------
  121. void ctkQImageViewPrivate::fitImageRectangle( double x0,
  122. double x1, double y0, double y1 )
  123. {
  124. if( this->SliceNumber >= 0 && this->SliceNumber < this->ImageList.size() )
  125. {
  126. this->TmpXMin = this->clamp( x0, 0,
  127. this->ImageList[ this->SliceNumber ].width() );
  128. this->TmpXMax = this->clamp( x1, this->TmpXMin,
  129. this->ImageList[ this->SliceNumber ].width() );
  130. this->TmpYMin = this->clamp( y0, 0,
  131. this->ImageList[ this->SliceNumber ].height() );
  132. this->TmpYMax = this->clamp( y1, this->TmpYMin,
  133. this->ImageList[ this->SliceNumber ].height() );
  134. this->CenterX = ( this->TmpXMax + this->TmpXMin ) / 2.0;
  135. this->CenterY = ( this->TmpYMax + this->TmpYMin ) / 2.0;
  136. }
  137. }
  138. // -------------------------------------------------------------------------
  139. ctkQImageView::ctkQImageView( QWidget* _parent )
  140. : Superclass( _parent ),
  141. d_ptr( new ctkQImageViewPrivate( *this ) )
  142. {
  143. Q_D( ctkQImageView );
  144. d->init();
  145. d->TmpXMax = this->width();
  146. d->TmpYMax = this->height();
  147. }
  148. // -------------------------------------------------------------------------
  149. ctkQImageView::ctkQImageView(
  150. ctkQImageViewPrivate& pvt,
  151. QWidget* _parent)
  152. : Superclass(_parent), d_ptr(&pvt)
  153. {
  154. Q_D(ctkQImageView);
  155. d->init();
  156. }
  157. // -------------------------------------------------------------------------
  158. ctkQImageView::~ctkQImageView()
  159. {
  160. }
  161. // -------------------------------------------------------------------------
  162. void ctkQImageView::addImage( const QImage & image )
  163. {
  164. Q_D( ctkQImageView );
  165. d->ImageList.push_back( image );
  166. d->TmpXMin = 0;
  167. d->TmpXMax = image.width();
  168. d->TmpYMin = 0;
  169. d->TmpYMax = image.height();
  170. this->update( true, false );
  171. this->setCenter( image.width()/2.0, image.height()/2.0 );
  172. }
  173. // -------------------------------------------------------------------------
  174. void ctkQImageView::clearImages( void )
  175. {
  176. Q_D( ctkQImageView );
  177. d->ImageList.clear();
  178. this->update( true, true );
  179. }
  180. // -------------------------------------------------------------------------
  181. double ctkQImageView::xSpacing( void )
  182. {
  183. Q_D( ctkQImageView );
  184. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  185. {
  186. return( 1000.0 / d->ImageList[ d->SliceNumber ].dotsPerMeterX() );
  187. }
  188. else
  189. {
  190. return 1;
  191. }
  192. }
  193. // -------------------------------------------------------------------------
  194. double ctkQImageView::ySpacing( void )
  195. {
  196. Q_D( ctkQImageView );
  197. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  198. {
  199. return( 1000.0 / d->ImageList[ d->SliceNumber ].dotsPerMeterY() );
  200. }
  201. else
  202. {
  203. return 1;
  204. }
  205. }
  206. // -------------------------------------------------------------------------
  207. double ctkQImageView::sliceThickness( void )
  208. {
  209. return 1;
  210. }
  211. // -------------------------------------------------------------------------
  212. double ctkQImageView::xPosition( void )
  213. {
  214. Q_D( ctkQImageView );
  215. return d->PositionX;
  216. }
  217. // -------------------------------------------------------------------------
  218. double ctkQImageView::yPosition( void )
  219. {
  220. Q_D( ctkQImageView );
  221. return d->PositionY;
  222. }
  223. // -------------------------------------------------------------------------
  224. double ctkQImageView::slicePosition( void )
  225. {
  226. Q_D( ctkQImageView );
  227. return d->SliceNumber;
  228. }
  229. // -------------------------------------------------------------------------
  230. double ctkQImageView::positionValue( void )
  231. {
  232. Q_D( ctkQImageView );
  233. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  234. {
  235. QColor vc( d->ImageList[ d->SliceNumber ].pixel( d->PositionX,
  236. d->PositionY ) );
  237. return vc.value();
  238. }
  239. return 0;
  240. }
  241. // -------------------------------------------------------------------------
  242. double ctkQImageView::xCenter( void )
  243. {
  244. Q_D( ctkQImageView );
  245. return d->CenterX;
  246. }
  247. // -------------------------------------------------------------------------
  248. double ctkQImageView::yCenter( void )
  249. {
  250. Q_D( ctkQImageView );
  251. return d->CenterY;
  252. }
  253. // -------------------------------------------------------------------------
  254. void ctkQImageView::setSliceNumber( int slicenum )
  255. {
  256. Q_D( ctkQImageView );
  257. if( slicenum >= 0 && slicenum < d->ImageList.size()
  258. && slicenum != d->SliceNumber )
  259. {
  260. d->SliceNumber = slicenum;
  261. emit this->sliceNumberChanged( slicenum );
  262. emit this->xSpacingChanged( this->xSpacing() );
  263. emit this->ySpacingChanged( this->ySpacing() );
  264. emit this->sliceThicknessChanged( this->sliceThickness() );
  265. emit this->slicePositionChanged( this->slicePosition() );
  266. this->update( false, false );
  267. }
  268. }
  269. //
  270. // -------------------------------------------------------------------------
  271. int ctkQImageView::sliceNumber( void ) const
  272. {
  273. Q_D( const ctkQImageView );
  274. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  275. {
  276. return d->SliceNumber;
  277. }
  278. else
  279. {
  280. return -1;
  281. }
  282. }
  283. // -------------------------------------------------------------------------
  284. void ctkQImageView::setIntensityWindow( double iwMin, double iwMax )
  285. {
  286. Q_D( ctkQImageView );
  287. if( iwMin != d->IntensityWindowMin )
  288. {
  289. d->IntensityWindowMin = iwMin;
  290. d->IntensityWindowMax = iwMax;
  291. emit this->intensityWindowMinChanged( iwMin );
  292. emit this->intensityWindowMaxChanged( iwMax );
  293. this->update( false, false );
  294. }
  295. }
  296. // -------------------------------------------------------------------------
  297. double ctkQImageView::intensityWindowMin( void ) const
  298. {
  299. Q_D( const ctkQImageView );
  300. return d->IntensityWindowMin;
  301. }
  302. // -------------------------------------------------------------------------
  303. double ctkQImageView::intensityWindowMax( void ) const
  304. {
  305. Q_D( const ctkQImageView );
  306. return d->IntensityWindowMax;
  307. }
  308. // -------------------------------------------------------------------------
  309. void ctkQImageView::setFlipXAxis( bool flip )
  310. {
  311. Q_D( ctkQImageView );
  312. if( flip != d->FlipXAxis )
  313. {
  314. d->FlipXAxis = flip;
  315. emit this->flipXAxisChanged( flip );
  316. this->update( false, false );
  317. }
  318. }
  319. // -------------------------------------------------------------------------
  320. bool ctkQImageView::flipXAxis( void ) const
  321. {
  322. Q_D( const ctkQImageView );
  323. return d->FlipXAxis;
  324. }
  325. // -------------------------------------------------------------------------
  326. void ctkQImageView::setFlipYAxis( bool flip )
  327. {
  328. Q_D( ctkQImageView );
  329. if( flip != d->FlipYAxis )
  330. {
  331. d->FlipYAxis = flip;
  332. emit this->flipYAxisChanged( flip );
  333. this->update( false, false );
  334. }
  335. }
  336. // -------------------------------------------------------------------------
  337. bool ctkQImageView::flipYAxis( void ) const
  338. {
  339. Q_D( const ctkQImageView );
  340. return d->FlipYAxis;
  341. }
  342. // -------------------------------------------------------------------------
  343. void ctkQImageView::setTransposeXY( bool transpose )
  344. {
  345. Q_D( ctkQImageView );
  346. if( transpose != d->TransposeXY )
  347. {
  348. d->TransposeXY = transpose;
  349. emit this->transposeXYChanged( transpose );
  350. this->update( false, false );
  351. }
  352. }
  353. // -------------------------------------------------------------------------
  354. bool ctkQImageView::transposeXY( void ) const
  355. {
  356. Q_D( const ctkQImageView );
  357. return d->TransposeXY;
  358. }
  359. // -------------------------------------------------------------------------
  360. void ctkQImageView::setCenter( double x, double y )
  361. {
  362. Q_D( ctkQImageView );
  363. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  364. {
  365. int tmpXRange = d->TmpXMax - d->TmpXMin;
  366. if( tmpXRange > d->ImageList[ d->SliceNumber ].width() )
  367. {
  368. tmpXRange = d->ImageList[ d->SliceNumber ].width();
  369. }
  370. int tmpYRange = d->TmpYMax - d->TmpYMin;
  371. if( tmpYRange > d->ImageList[ d->SliceNumber ].height() )
  372. {
  373. tmpYRange = d->ImageList[ d->SliceNumber ].height();
  374. }
  375. int xMin2 = static_cast<int>(x) - tmpXRange/2.0;
  376. if( xMin2 < 0 )
  377. {
  378. xMin2 = 0;
  379. }
  380. int xMax2 = xMin2 + tmpXRange;
  381. if( xMax2 > d->ImageList[ d->SliceNumber ].width() )
  382. {
  383. xMax2 = d->ImageList[ d->SliceNumber ].width();
  384. xMin2 = xMax2 - tmpXRange;
  385. }
  386. int yMin2 = static_cast<int>(y) - tmpYRange/2.0;
  387. if( yMin2 < 0 )
  388. {
  389. yMin2 = 0;
  390. }
  391. int yMax2 = yMin2 + tmpYRange;
  392. if( yMax2 > d->ImageList[ d->SliceNumber ].height() )
  393. {
  394. yMax2 = d->ImageList[ d->SliceNumber ].height();
  395. yMin2 = yMax2 - tmpYRange;
  396. }
  397. d->fitImageRectangle( xMin2, xMax2, yMin2, yMax2 );
  398. emit this->xCenterChanged( x );
  399. emit this->yCenterChanged( y );
  400. this->update( false, false );
  401. }
  402. }
  403. // -------------------------------------------------------------------------
  404. void ctkQImageView::setPosition( double x, double y )
  405. {
  406. Q_D( ctkQImageView );
  407. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  408. {
  409. d->PositionX = x;
  410. d->PositionY = y;
  411. emit this->xPositionChanged( x );
  412. emit this->yPositionChanged( y );
  413. emit this->positionValueChanged( this->positionValue() );
  414. this->update( false, false );
  415. }
  416. }
  417. // -------------------------------------------------------------------------
  418. double ctkQImageView::zoom( void )
  419. {
  420. Q_D( ctkQImageView );
  421. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  422. {
  423. return d->Zoom;
  424. }
  425. return 1;
  426. }
  427. // -------------------------------------------------------------------------
  428. void ctkQImageView::setZoom( double factor )
  429. {
  430. Q_D( ctkQImageView );
  431. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  432. {
  433. const QImage * img = & d->ImageList[ d->SliceNumber ];
  434. if( factor < 2.0 / img->width() )
  435. {
  436. factor = 2.0 / img->width();
  437. }
  438. if( factor > img->width()/2.0 )
  439. {
  440. factor = img->width()/2.0;
  441. }
  442. d->Zoom = factor;
  443. double cx = ( d->TmpXMin + d->TmpXMax ) / 2.0;
  444. double cy = ( d->TmpYMin + d->TmpYMax ) / 2.0;
  445. double x2 = img->width() / factor;
  446. double y2 = img->height() / factor;
  447. //double x2 = ( d->TmpXMax - d->TmpXMin ) / 2.0;
  448. //double y2 = ( d->TmpYMax - d->TmpYMin ) / 2.0;
  449. int xMin2 = static_cast<int>(cx) - x2 / 2.0;
  450. if( xMin2 < 0 )
  451. {
  452. xMin2 = 0;
  453. }
  454. int xMax2 = xMin2 + x2;
  455. if( xMax2 > d->ImageList[ d->SliceNumber ].width() )
  456. {
  457. xMax2 = d->ImageList[ d->SliceNumber ].width();
  458. xMin2 = xMax2 - x2;
  459. }
  460. int yMin2 = static_cast<int>(cy) - y2 / 2.0;
  461. if( yMin2 < 0 )
  462. {
  463. yMin2 = 0;
  464. }
  465. int yMax2 = yMin2 + y2;
  466. if( yMax2 > d->ImageList[ d->SliceNumber ].height() )
  467. {
  468. yMax2 = d->ImageList[ d->SliceNumber ].height();
  469. yMin2 = yMax2 - y2;
  470. }
  471. d->fitImageRectangle( xMin2, xMax2, yMin2, yMax2 );
  472. this->update( true, true );
  473. }
  474. }
  475. // -------------------------------------------------------------------------
  476. void ctkQImageView::reset( )
  477. {
  478. Q_D( ctkQImageView );
  479. if( d->ImageList.size() > 0 )
  480. {
  481. if( d->SliceNumber < 0 )
  482. {
  483. this->setSliceNumber( 0 );
  484. }
  485. }
  486. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  487. {
  488. d->fitImageRectangle( 0, 0, d->ImageList[ d->SliceNumber ].width(),
  489. d->ImageList[ d->SliceNumber ].height() );
  490. this->update( true, true );
  491. }
  492. }
  493. // -------------------------------------------------------------------------
  494. void ctkQImageView::keyPressEvent( QKeyEvent * event )
  495. {
  496. Q_D( ctkQImageView );
  497. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  498. {
  499. switch( event->key() )
  500. {
  501. case Qt::Key_R:
  502. {
  503. this->reset();
  504. break;
  505. }
  506. case Qt::Key_Up:
  507. {
  508. this->setSliceNumber( d->SliceNumber+1 );
  509. break;
  510. }
  511. case Qt::Key_Down:
  512. {
  513. this->setSliceNumber( d->SliceNumber-1 );
  514. break;
  515. }
  516. default:
  517. {
  518. event->ignore();
  519. }
  520. };
  521. }
  522. }
  523. // -------------------------------------------------------------------------
  524. void ctkQImageView::mousePressEvent( QMouseEvent * event )
  525. {
  526. Q_D( ctkQImageView );
  527. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  528. {
  529. switch( event->button() )
  530. {
  531. case Qt::LeftButton:
  532. {
  533. d->MouseLeftDragging = true;
  534. d->MouseLastX = event->x();
  535. d->MouseLastY = event->y();
  536. d->MouseLastIntensityWindowMin = this->intensityWindowMin();
  537. d->MouseLastIntensityWindowMax = this->intensityWindowMax();
  538. break;
  539. }
  540. case Qt::MidButton:
  541. {
  542. d->MouseMiddleDragging = true;
  543. d->MouseLastX = event->x();
  544. d->MouseLastY = event->y();
  545. d->MouseLastZoom = this->zoom();
  546. break;
  547. }
  548. case Qt::RightButton:
  549. {
  550. d->MouseRightDragging = true;
  551. double relativeX = static_cast<double>( event->x() )
  552. / this->width();
  553. double relativeY = static_cast<double>( event->y() )
  554. / this->height();
  555. double x = (d->TmpXMax - d->TmpXMin) * relativeX + d->TmpXMin;
  556. double y = (d->TmpYMax - d->TmpYMin) * relativeY + d->TmpYMin;
  557. this->setCenter( x, y );
  558. break;
  559. }
  560. default:
  561. {
  562. event->ignore();
  563. }
  564. };
  565. }
  566. }
  567. // -------------------------------------------------------------------------
  568. void ctkQImageView::mouseReleaseEvent( QMouseEvent * event )
  569. {
  570. Q_D( ctkQImageView );
  571. d->MouseLeftDragging = false;
  572. d->MouseMiddleDragging = false;
  573. d->MouseRightDragging = false;
  574. event->ignore();
  575. }
  576. // -------------------------------------------------------------------------
  577. void ctkQImageView::mouseMoveEvent( QMouseEvent * event )
  578. {
  579. Q_D( ctkQImageView );
  580. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  581. {
  582. if( d->MouseLeftDragging )
  583. {
  584. double distX = d->MouseLastX - event->x();
  585. double distY = d->MouseLastY - event->y();
  586. double deltaMin = ( distX / this->height() );
  587. if( deltaMin < 0 )
  588. {
  589. // Heuristic to make shrinking propotional to enlarging
  590. deltaMin *= -deltaMin;
  591. }
  592. double deltaMax = ( distY / this->width() );
  593. if( deltaMax < 0 )
  594. {
  595. // Heuristic to make shrinking propotional to enlarging
  596. deltaMax *= -deltaMax;
  597. }
  598. double iRange = d->MouseLastIntensityWindowMax
  599. - d->MouseLastIntensityWindowMin;
  600. deltaMin *= iRange;
  601. deltaMax *= iRange;
  602. double newMin = d->MouseLastIntensityWindowMin + deltaMin;
  603. double newMax = d->MouseLastIntensityWindowMax + deltaMax;
  604. this->setIntensityWindow( newMin, newMax );
  605. }
  606. else if( d->MouseMiddleDragging )
  607. {
  608. double distY = d->MouseLastY - event->y();
  609. double deltaZ = (distY / this->height());
  610. if( deltaZ < 0 )
  611. {
  612. // Heuristic to make shrinking propotional to enlarging
  613. deltaZ *= -deltaZ;
  614. }
  615. double newZoom = d->MouseLastZoom + deltaZ;
  616. this->setZoom( newZoom );
  617. }
  618. else
  619. {
  620. double relativeX = static_cast<double>( event->x() )
  621. / this->width();
  622. double relativeY = static_cast<double>( event->y() )
  623. / this->height();
  624. double x = (d->TmpXMax - d->TmpXMin) * relativeX + d->TmpXMin;
  625. double y = (d->TmpYMax - d->TmpYMin) * relativeY + d->TmpYMin;
  626. this->setPosition( x, y );
  627. }
  628. }
  629. }
  630. // -------------------------------------------------------------------------
  631. void ctkQImageView::enterEvent( QEvent * )
  632. {
  633. Q_D( ctkQImageView );
  634. QApplication::setOverrideCursor( QCursor(Qt::CrossCursor) );
  635. d->Window->grabKeyboard();
  636. }
  637. // -------------------------------------------------------------------------
  638. void ctkQImageView::leaveEvent( QEvent * )
  639. {
  640. Q_D( ctkQImageView );
  641. QApplication::restoreOverrideCursor();
  642. d->Window->releaseKeyboard();
  643. }
  644. // -------------------------------------------------------------------------
  645. void ctkQImageView::resizeEvent( QResizeEvent* event )
  646. {
  647. this->Superclass::resizeEvent( event );
  648. this->update( false, true );
  649. }
  650. // -------------------------------------------------------------------------
  651. void ctkQImageView::update( bool zoomChanged,
  652. bool sizeChanged )
  653. {
  654. Q_D( ctkQImageView );
  655. if( d->SliceNumber >= 0 && d->SliceNumber < d->ImageList.size() )
  656. {
  657. const QImage * img = & ( d->ImageList[ d->SliceNumber ] );
  658. if( zoomChanged || sizeChanged )
  659. {
  660. if( this->width() > 0 && this->height() > 0
  661. && d->TmpXMax > d->TmpXMin && d->TmpYMax > d->TmpYMin)
  662. {
  663. int tmpXRange = d->TmpXMax - d->TmpXMin;
  664. int tmpYRange = d->TmpYMax - d->TmpYMin;
  665. double tmpAspectRatio = static_cast<double>(tmpYRange) / tmpXRange;
  666. double screenAspectRatio = static_cast<double>(this->height())
  667. / this->width();
  668. if( screenAspectRatio > tmpAspectRatio )
  669. {
  670. int extraTmpYAbove = d->TmpYMin;
  671. int extraTmpYBelow = img->height() - d->TmpYMax;
  672. int extraTmpYNeeded = tmpXRange * screenAspectRatio
  673. - tmpYRange;
  674. int minExtra = extraTmpYAbove;
  675. if( extraTmpYBelow < minExtra )
  676. {
  677. minExtra = extraTmpYBelow;
  678. }
  679. if(2 * minExtra >= extraTmpYNeeded)
  680. {
  681. int minNeeded = extraTmpYNeeded / 2.0;
  682. int maxNeeded = extraTmpYNeeded - minNeeded;
  683. d->TmpYMin -= minNeeded;
  684. d->TmpYMax += maxNeeded;
  685. }
  686. else if(extraTmpYAbove + extraTmpYBelow >= extraTmpYNeeded)
  687. {
  688. if(extraTmpYAbove < extraTmpYBelow)
  689. {
  690. d->TmpYMin = 0;
  691. d->TmpYMax += extraTmpYNeeded - extraTmpYAbove;
  692. }
  693. else
  694. {
  695. d->TmpYMax = img->height();
  696. d->TmpYMin -= extraTmpYNeeded - extraTmpYBelow;
  697. }
  698. }
  699. else
  700. {
  701. d->TmpYMin = 0;
  702. d->TmpYMax = img->height();
  703. }
  704. d->TmpImage = QPixmap( this->width(),
  705. static_cast<unsigned int>(
  706. static_cast<double>(d->TmpYMax - d->TmpYMin)
  707. / (d->TmpXMax - d->TmpXMin)
  708. * this->width() + 0.5 ) );
  709. }
  710. else if(screenAspectRatio < tmpAspectRatio)
  711. {
  712. int extraTmpXLeft = d->TmpXMin;
  713. int extraTmpXRight = img->width() - d->TmpXMax;
  714. int extraTmpXNeeded = static_cast<double>(tmpYRange)
  715. / screenAspectRatio - tmpXRange;
  716. int minExtra = extraTmpXLeft;
  717. if( extraTmpXRight < minExtra )
  718. {
  719. minExtra = extraTmpXRight;
  720. }
  721. if(2 * minExtra >= extraTmpXNeeded)
  722. {
  723. int minNeeded = extraTmpXNeeded / 2.0;
  724. int maxNeeded = extraTmpXNeeded - minNeeded;
  725. d->TmpXMin -= minNeeded;
  726. d->TmpXMax += maxNeeded;
  727. }
  728. else if(extraTmpXLeft + extraTmpXRight >= extraTmpXNeeded)
  729. {
  730. if(extraTmpXLeft < extraTmpXRight)
  731. {
  732. d->TmpXMin = 0;
  733. d->TmpXMax += extraTmpXNeeded - extraTmpXLeft;
  734. }
  735. else
  736. {
  737. d->TmpXMax = img->width();
  738. d->TmpXMin -= extraTmpXNeeded - extraTmpXRight;
  739. }
  740. }
  741. else
  742. {
  743. d->TmpXMin = 0;
  744. d->TmpXMax = img->width();
  745. }
  746. d->TmpImage = QPixmap( static_cast<unsigned int>( this->height()
  747. / ( static_cast<double>(d->TmpYMax - d->TmpYMin)
  748. / (d->TmpXMax - d->TmpXMin) )
  749. + 0.5 ), this->height() );
  750. }
  751. else
  752. {
  753. d->TmpImage = QPixmap( this->width(), this->height() );
  754. }
  755. }
  756. }
  757. if( d->TmpImage.width() > 0 && d->TmpImage.height() > 0)
  758. {
  759. QPainter painter( &(d->TmpImage) );
  760. painter.drawPixmap( 0, 0, d->TmpImage.width(), d->TmpImage.height(),
  761. QPixmap::fromImage(*img), d->TmpXMin, d->TmpYMin,
  762. d->TmpXMax - d->TmpXMin, d->TmpYMax - d->TmpYMin);
  763. }
  764. d->Window->setPixmap( d->TmpImage );
  765. }
  766. else
  767. {
  768. d->Window->setText( "No Image Loaded." );
  769. }
  770. }