TDE graphics utilities
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kpview.cpp 53KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910
  1. /*
  2. Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions
  6. are met:
  7. 1. Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. 2. Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in the
  11. documentation and/or other materials provided with the distribution.
  12. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  13. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  14. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  15. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  16. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  17. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  18. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  19. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  21. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #define DEBUG_KP_VIEW 0
  24. #define DEBUG_KP_VIEW_RENDERER ((DEBUG_KP_VIEW && 0) || 0)
  25. #include <kpview.h>
  26. #include <math.h>
  27. #include <stdlib.h>
  28. #include <tqbitmap.h>
  29. #include <tqcursor.h>
  30. #include <tqdragobject.h>
  31. #include <tqguardedptr.h>
  32. #include <tqimage.h>
  33. #include <tqpainter.h>
  34. #include <tqpixmap.h>
  35. #include <tqpoint.h>
  36. #include <tqrect.h>
  37. #include <tqregion.h>
  38. #include <tqmemarray.h>
  39. #if DEBUG_KP_VIEW || DEBUG_KP_VIEW_RENDERER
  40. #include <tqdatetime.h>
  41. #endif
  42. #include <kdebug.h>
  43. #include <kpdefs.h>
  44. #include <kpdocument.h>
  45. #include <kppixmapfx.h>
  46. #include <kpselection.h>
  47. #include <kptemppixmap.h>
  48. #include <kptool.h>
  49. #include <kptooltoolbar.h>
  50. #include <kpviewmanager.h>
  51. #include <kpviewscrollablecontainer.h>
  52. struct kpViewPrivate
  53. {
  54. // sync: kpView::paintEvent()
  55. //
  56. // Normally, these pointers must be valid while the kpView is alive.
  57. // Generally, the objects they point to are deleted only after kpView
  58. // is deleted.
  59. //
  60. // However, sometimes we use deleteLater() for the kpView.
  61. // Before the delayed deletion is executed, those objects are deleted
  62. // and then our paintEvent() is called. paintEvent() must therefore
  63. // have some way of realising that those objects have been deleted so
  64. // we use guardded pointers.
  65. //
  66. // For more details, see SVN commit:
  67. // "r385274 | dang | 2005-02-02 22:08:27 +1100 (Wed, 02 Feb 2005) | 21 lines".
  68. TQGuardedPtr <kpDocument> m_document;
  69. TQGuardedPtr <kpToolToolBar> m_toolToolBar;
  70. TQGuardedPtr <kpViewManager> m_viewManager;
  71. TQGuardedPtr <kpView> m_buddyView;
  72. TQGuardedPtr <kpViewScrollableContainer> m_scrollableContainer;
  73. int m_hzoom, m_vzoom;
  74. TQPoint m_origin;
  75. bool m_showGrid;
  76. bool m_isBuddyViewScrollableContainerRectangleShown;
  77. TQRect m_buddyViewScrollableContainerRectangle;
  78. TQRegion m_queuedUpdateArea;
  79. TQPixmap *m_backBuffer;
  80. };
  81. kpView::kpView (kpDocument *document,
  82. kpToolToolBar *toolToolBar,
  83. kpViewManager *viewManager,
  84. kpView *buddyView,
  85. kpViewScrollableContainer *scrollableContainer,
  86. TQWidget *parent, const char *name)
  87. : TQWidget (parent, name, TQt::WNoAutoErase/*no flicker*/),
  88. d (new kpViewPrivate ())
  89. {
  90. d->m_document = document;
  91. d->m_toolToolBar = toolToolBar;
  92. d->m_viewManager = viewManager;
  93. d->m_buddyView = buddyView;
  94. d->m_scrollableContainer = scrollableContainer;
  95. d->m_hzoom = 100, d->m_vzoom = 100;
  96. d->m_origin = TQPoint (0, 0);
  97. d->m_showGrid = false;
  98. d->m_isBuddyViewScrollableContainerRectangleShown = false;
  99. d->m_backBuffer = 0;
  100. setBackgroundMode (TQt::NoBackground); // no flicker
  101. setFocusPolicy (TQ_WheelFocus);
  102. setMouseTracking (true); // mouseMoveEvent's even when no mousebtn down
  103. setKeyCompression (true);
  104. setInputMethodEnabled (true); // ensure using InputMethod
  105. }
  106. kpView::~kpView ()
  107. {
  108. setHasMouse (false);
  109. delete d->m_backBuffer;
  110. delete d;
  111. }
  112. // public
  113. kpDocument *kpView::document () const
  114. {
  115. return d->m_document;
  116. }
  117. // protected
  118. kpSelection *kpView::selection () const
  119. {
  120. return document () ? document ()->selection () : 0;
  121. }
  122. // public
  123. kpToolToolBar *kpView::toolToolBar () const
  124. {
  125. return d->m_toolToolBar;
  126. }
  127. // protected
  128. kpTool *kpView::tool () const
  129. {
  130. return toolToolBar () ? toolToolBar ()->tool () : 0;
  131. }
  132. // public
  133. kpViewManager *kpView::viewManager () const
  134. {
  135. return d->m_viewManager;
  136. }
  137. // public
  138. kpView *kpView::buddyView () const
  139. {
  140. return d->m_buddyView;
  141. }
  142. // public
  143. kpViewScrollableContainer *kpView::buddyViewScrollableContainer () const
  144. {
  145. return (buddyView () ? buddyView ()->scrollableContainer () : 0);
  146. }
  147. // public
  148. kpViewScrollableContainer *kpView::scrollableContainer () const
  149. {
  150. return d->m_scrollableContainer;
  151. }
  152. // public
  153. int kpView::zoomLevelX (void) const
  154. {
  155. return d->m_hzoom;
  156. }
  157. // public
  158. int kpView::zoomLevelY (void) const
  159. {
  160. return d->m_vzoom;
  161. }
  162. // public virtual
  163. void kpView::setZoomLevel (int hzoom, int vzoom)
  164. {
  165. if (hzoom == d->m_hzoom && vzoom == d->m_vzoom)
  166. return;
  167. if (hzoom <= 0 || vzoom <= 0)
  168. return;
  169. d->m_hzoom = hzoom;
  170. d->m_vzoom = vzoom;
  171. if (viewManager ())
  172. viewManager ()->updateView (this);
  173. emit zoomLevelChanged (hzoom, vzoom);
  174. }
  175. // public
  176. TQPoint kpView::origin () const
  177. {
  178. return d->m_origin;
  179. }
  180. // public virtual
  181. void kpView::setOrigin (const TQPoint &origin)
  182. {
  183. #if DEBUG_KP_VIEW
  184. kdDebug () << "kpView(" << name () << ")::setOrigin" << origin << endl;
  185. #endif
  186. if (origin == d->m_origin)
  187. {
  188. #if DEBUG_KP_VIEW
  189. kdDebug () << "\tNOP" << endl;
  190. #endif
  191. return;
  192. }
  193. d->m_origin = origin;
  194. if (viewManager ())
  195. viewManager ()->updateView (this);
  196. emit originChanged (origin);
  197. }
  198. // public
  199. bool kpView::canShowGrid () const
  200. {
  201. // (minimum zoom level < 400% would probably be reported as a bug by
  202. // users who thought that the grid was a part of the image!)
  203. return ((zoomLevelX () >= 400 && zoomLevelX () % 100 == 0) &&
  204. (zoomLevelY () >= 400 && zoomLevelY () % 100 == 0));
  205. }
  206. // public
  207. bool kpView::isGridShown () const
  208. {
  209. return d->m_showGrid;
  210. }
  211. // public
  212. void kpView::showGrid (bool yes)
  213. {
  214. if (d->m_showGrid == yes)
  215. return;
  216. if (yes && !canShowGrid ())
  217. return;
  218. d->m_showGrid = yes;
  219. if (viewManager ())
  220. viewManager ()->updateView (this);
  221. }
  222. // public
  223. bool kpView::isBuddyViewScrollableContainerRectangleShown () const
  224. {
  225. return d->m_isBuddyViewScrollableContainerRectangleShown;
  226. }
  227. // public
  228. void kpView::showBuddyViewScrollableContainerRectangle (bool yes)
  229. {
  230. if (yes == d->m_isBuddyViewScrollableContainerRectangleShown)
  231. return;
  232. d->m_isBuddyViewScrollableContainerRectangleShown = yes;
  233. if (d->m_isBuddyViewScrollableContainerRectangleShown)
  234. {
  235. // Got these connect statements by analysing deps of
  236. // updateBuddyViewScrollableContainerRectangle() rect update code.
  237. connect (this, TQT_SIGNAL (zoomLevelChanged (int, int)),
  238. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  239. connect (this, TQT_SIGNAL (originChanged (const TQPoint &)),
  240. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  241. if (buddyViewScrollableContainer ())
  242. {
  243. connect (buddyViewScrollableContainer (), TQT_SIGNAL (contentsMovingSoon (int, int)),
  244. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  245. connect (buddyViewScrollableContainer (), TQT_SIGNAL (resized ()),
  246. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  247. }
  248. if (buddyView ())
  249. {
  250. connect (buddyView (), TQT_SIGNAL (zoomLevelChanged (int, int)),
  251. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  252. connect (buddyView (), TQT_SIGNAL (originChanged (const TQPoint &)),
  253. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  254. connect (buddyView (), TQT_SIGNAL (sizeChanged (int, int)),
  255. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  256. }
  257. }
  258. else
  259. {
  260. disconnect (this, TQT_SIGNAL (zoomLevelChanged (int, int)),
  261. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  262. disconnect (this, TQT_SIGNAL (originChanged (const TQPoint &)),
  263. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  264. if (buddyViewScrollableContainer ())
  265. {
  266. disconnect (buddyViewScrollableContainer (), TQT_SIGNAL (contentsMovingSoon (int, int)),
  267. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  268. disconnect (buddyViewScrollableContainer (), TQT_SIGNAL (resized ()),
  269. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  270. }
  271. if (buddyView ())
  272. {
  273. disconnect (buddyView (), TQT_SIGNAL (zoomLevelChanged (int, int)),
  274. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  275. disconnect (buddyView (), TQT_SIGNAL (originChanged (const TQPoint &)),
  276. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  277. disconnect (buddyView (), TQT_SIGNAL (sizeChanged (int, int)),
  278. this, TQT_SLOT (updateBuddyViewScrollableContainerRectangle ()));
  279. }
  280. }
  281. updateBuddyViewScrollableContainerRectangle ();
  282. }
  283. // protected
  284. TQRect kpView::buddyViewScrollableContainerRectangle () const
  285. {
  286. return d->m_buddyViewScrollableContainerRectangle;
  287. }
  288. // protected slot
  289. void kpView::updateBuddyViewScrollableContainerRectangle ()
  290. {
  291. if (viewManager ())
  292. viewManager ()->setQueueUpdates ();
  293. {
  294. if (d->m_buddyViewScrollableContainerRectangle.isValid ())
  295. {
  296. if (viewManager ())
  297. {
  298. // Erase last
  299. viewManager ()->updateViewRectangleEdges (this,
  300. d->m_buddyViewScrollableContainerRectangle);
  301. }
  302. }
  303. TQRect newRect;
  304. if (isBuddyViewScrollableContainerRectangleShown () &&
  305. buddyViewScrollableContainer () && buddyView ())
  306. {
  307. TQRect docRect = buddyView ()->transformViewToDoc (
  308. TQRect (buddyViewScrollableContainer ()->contentsXSoon (),
  309. buddyViewScrollableContainer ()->contentsYSoon (),
  310. TQMIN (buddyView ()->width (),
  311. buddyViewScrollableContainer ()->visibleWidth ()),
  312. TQMIN (buddyView ()->height (),
  313. buddyViewScrollableContainer ()->visibleHeight ())));
  314. TQRect viewRect = this->transformDocToView (docRect);
  315. // (Surround the area of interest by moving outwards by 1 pixel in each
  316. // direction - don't overlap area)
  317. newRect = TQRect (viewRect.x () - 1,
  318. viewRect.y () - 1,
  319. viewRect.width () + 2,
  320. viewRect.height () + 2);
  321. }
  322. else
  323. {
  324. newRect = TQRect ();
  325. }
  326. if (newRect != d->m_buddyViewScrollableContainerRectangle)
  327. {
  328. // (must set before updateView() for paintEvent() to see new
  329. // rect)
  330. d->m_buddyViewScrollableContainerRectangle = newRect;
  331. if (newRect.isValid ())
  332. {
  333. if (viewManager ())
  334. {
  335. viewManager ()->updateViewRectangleEdges (this,
  336. d->m_buddyViewScrollableContainerRectangle);
  337. }
  338. }
  339. }
  340. }
  341. if (viewManager ())
  342. viewManager ()->restoreQueueUpdates ();
  343. }
  344. // public
  345. double kpView::transformViewToDocX (double viewX) const
  346. {
  347. return (viewX - origin ().x ()) * 100.0 / zoomLevelX ();
  348. }
  349. // public
  350. double kpView::transformViewToDocY (double viewY) const
  351. {
  352. return (viewY - origin ().y ()) * 100.0 / zoomLevelY ();
  353. }
  354. // public
  355. TQPoint kpView::transformViewToDoc (const TQPoint &viewPoint) const
  356. {
  357. return TQPoint ((int) transformViewToDocX (viewPoint.x ()),
  358. (int) transformViewToDocY (viewPoint.y ()));
  359. }
  360. // public
  361. TQRect kpView::transformViewToDoc (const TQRect &viewRect) const
  362. {
  363. if (zoomLevelX () == 100 && zoomLevelY () == 100)
  364. {
  365. return TQRect (viewRect.x () - origin ().x (),
  366. viewRect.y () - origin ().y (),
  367. viewRect.width (),
  368. viewRect.height ());
  369. }
  370. else
  371. {
  372. const TQPoint docTopLeft = transformViewToDoc (viewRect.topLeft ());
  373. // (don't call transformViewToDoc[XY]() - need to round up dimensions)
  374. const int docWidth = tqRound (double (viewRect.width ()) * 100.0 / double (zoomLevelX ()));
  375. const int docHeight = tqRound (double (viewRect.height ()) * 100.0 / double (zoomLevelY ()));
  376. // (like TQWMatrix::Areas)
  377. return TQRect (docTopLeft.x (), docTopLeft.y (), docWidth, docHeight);
  378. }
  379. }
  380. // public
  381. double kpView::transformDocToViewX (double docX) const
  382. {
  383. return (docX * zoomLevelX () / 100.0) + origin ().x ();
  384. }
  385. // public
  386. double kpView::transformDocToViewY (double docY) const
  387. {
  388. return (docY * zoomLevelY () / 100.0) + origin ().y ();
  389. }
  390. // public
  391. TQPoint kpView::transformDocToView (const TQPoint &docPoint) const
  392. {
  393. return TQPoint ((int) transformDocToViewX (docPoint.x ()),
  394. (int) transformDocToViewY (docPoint.y ()));
  395. }
  396. // public
  397. TQRect kpView::transformDocToView (const TQRect &docRect) const
  398. {
  399. if (zoomLevelX () == 100 && zoomLevelY () == 100)
  400. {
  401. return TQRect (docRect.x () + origin ().x (),
  402. docRect.y () + origin ().y (),
  403. docRect.width (),
  404. docRect.height ());
  405. }
  406. else
  407. {
  408. const TQPoint viewTopLeft = transformDocToView (docRect.topLeft ());
  409. // (don't call transformDocToView[XY]() - need to round up dimensions)
  410. const int viewWidth = tqRound (double (docRect.width ()) * double (zoomLevelX ()) / 100.0);
  411. const int viewHeight = tqRound (double (docRect.height ()) * double (zoomLevelY ()) / 100.0);
  412. // (like TQWMatrix::Areas)
  413. return TQRect (viewTopLeft.x (), viewTopLeft.y (), viewWidth, viewHeight);
  414. }
  415. }
  416. // public
  417. TQPoint kpView::transformViewToOtherView (const TQPoint &viewPoint,
  418. const kpView *otherView)
  419. {
  420. if (this == otherView)
  421. return viewPoint;
  422. const double docX = transformViewToDocX (viewPoint.x ());
  423. const double docY = transformViewToDocY (viewPoint.y ());
  424. const double otherViewX = otherView->transformDocToViewX (docX);
  425. const double otherViewY = otherView->transformDocToViewY (docY);
  426. return TQPoint ((int) otherViewX, (int) otherViewY);
  427. }
  428. // public
  429. int kpView::zoomedDocWidth () const
  430. {
  431. return document () ? document ()->width () * zoomLevelX () / 100 : 0;
  432. }
  433. // public
  434. int kpView::zoomedDocHeight () const
  435. {
  436. return document () ? document ()->height () * zoomLevelY () / 100 : 0;
  437. }
  438. // public
  439. void kpView::setHasMouse (bool yes)
  440. {
  441. kpViewManager *vm = viewManager ();
  442. if (!vm)
  443. return;
  444. #if DEBUG_KP_VIEW && 0
  445. kdDebug () << "kpView(" << name ()
  446. << ")::setHasMouse(" << yes
  447. << ") existing viewUnderCursor="
  448. << (vm->viewUnderCursor () ? vm->viewUnderCursor ()->name () : "(none)")
  449. << endl;
  450. #endif
  451. if (yes && vm->viewUnderCursor () != this)
  452. vm->setViewUnderCursor (this);
  453. else if (!yes && vm->viewUnderCursor () == this)
  454. vm->setViewUnderCursor (0);
  455. }
  456. // public
  457. void kpView::addToQueuedArea (const TQRegion &region)
  458. {
  459. #if DEBUG_KP_VIEW && 0
  460. kdDebug () << "kpView(" << name ()
  461. << ")::addToQueuedArea() already=" << d->m_queuedUpdateArea
  462. << " - plus - " << region
  463. << endl;
  464. #endif
  465. d->m_queuedUpdateArea += region;
  466. }
  467. // public
  468. void kpView::addToQueuedArea (const TQRect &rect)
  469. {
  470. #if DEBUG_KP_VIEW && 0
  471. kdDebug () << "kpView(" << name ()
  472. << ")::addToQueuedArea() already=" << d->m_queuedUpdateArea
  473. << " - plus - " << rect
  474. << endl;
  475. #endif
  476. d->m_queuedUpdateArea += rect;
  477. }
  478. // public
  479. void kpView::invalidateQueuedArea ()
  480. {
  481. #if DEBUG_KP_VIEW && 0
  482. kdDebug () << "kpView::invalidateQueuedArea()" << endl;
  483. #endif
  484. d->m_queuedUpdateArea = TQRegion ();
  485. }
  486. // public
  487. void kpView::updateQueuedArea ()
  488. {
  489. kpViewManager *vm = viewManager ();
  490. #if DEBUG_KP_VIEW && 0
  491. kdDebug () << "kpView(" << name ()
  492. << ")::updateQueuedArea() vm=" << (bool) vm
  493. << " queueUpdates=" << (vm && vm->queueUpdates ())
  494. << " fastUpdates=" << (vm && vm->fastUpdates ())
  495. << " area=" << d->m_queuedUpdateArea
  496. << endl;
  497. #endif
  498. if (!vm)
  499. return;
  500. if (vm->queueUpdates ())
  501. return;
  502. if (!d->m_queuedUpdateArea.isNull ())
  503. vm->updateView (this, d->m_queuedUpdateArea);
  504. invalidateQueuedArea ();
  505. }
  506. // public
  507. void kpView::updateMicroFocusHint (const TQRect &microFocusHint)
  508. {
  509. int x = microFocusHint.topLeft().x();
  510. int y = microFocusHint.topLeft().y();
  511. int width = microFocusHint.width();
  512. int height = microFocusHint.height();
  513. setMicroFocusHint (x, y, width, height);
  514. }
  515. // public
  516. TQRect kpView::selectionViewRect () const
  517. {
  518. return selection () ?
  519. transformDocToView (selection ()->boundingRect ()) :
  520. TQRect ();
  521. }
  522. // public
  523. TQPoint kpView::mouseViewPoint (const TQPoint &returnViewPoint) const
  524. {
  525. if (returnViewPoint != KP_INVALID_POINT)
  526. return returnViewPoint;
  527. else
  528. return mapFromGlobal (TQCursor::pos ());
  529. }
  530. // public
  531. TQPoint kpView::mouseViewPointRelativeToSelection (const TQPoint &viewPoint) const
  532. {
  533. if (!selection ())
  534. return KP_INVALID_POINT;
  535. return mouseViewPoint (viewPoint) - transformDocToView (selection ()->topLeft ());
  536. }
  537. // public
  538. bool kpView::mouseOnSelection (const TQPoint &viewPoint) const
  539. {
  540. const TQRect selViewRect = selectionViewRect ();
  541. if (!selViewRect.isValid ())
  542. return false;
  543. return selViewRect.contains (mouseViewPoint (viewPoint));
  544. }
  545. // public
  546. int kpView::textSelectionMoveBorderAtomicSize () const
  547. {
  548. if (!selection () || !selection ()->isText ())
  549. return 0;
  550. return TQMAX (4, zoomLevelX () / 100);
  551. }
  552. // public
  553. bool kpView::mouseOnSelectionToMove (const TQPoint &viewPoint) const
  554. {
  555. if (!mouseOnSelection (viewPoint))
  556. return false;
  557. if (!selection ()->isText ())
  558. return true;
  559. if (mouseOnSelectionResizeHandle (viewPoint))
  560. return false;
  561. const TQPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint);
  562. // Middle point should always be selectable
  563. const TQPoint selCenterDocPoint = selection ()->boundingRect ().center ();
  564. if (tool () &&
  565. tool ()->currentPoint () == selCenterDocPoint)
  566. {
  567. return false;
  568. }
  569. const int atomicSize = textSelectionMoveBorderAtomicSize ();
  570. const TQRect selViewRect = selectionViewRect ();
  571. return (viewPointRelSel.x () < atomicSize ||
  572. viewPointRelSel.x () >= selViewRect.width () - atomicSize ||
  573. viewPointRelSel.y () < atomicSize ||
  574. viewPointRelSel.y () >= selViewRect.height () - atomicSize);
  575. }
  576. // protected
  577. bool kpView::selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize) const
  578. {
  579. if (!selection ())
  580. return false;
  581. const TQRect selViewRect = selectionViewRect ();
  582. return (selViewRect.width () >= atomicSize * 5 ||
  583. selViewRect.height () >= atomicSize * 5);
  584. }
  585. // public
  586. int kpView::selectionResizeHandleAtomicSize () const
  587. {
  588. int atomicSize = TQMIN (7, TQMAX (4, zoomLevelX () / 100));
  589. while (atomicSize > 0 &&
  590. !selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (atomicSize))
  591. {
  592. atomicSize--;
  593. }
  594. return atomicSize;
  595. }
  596. // public
  597. bool kpView::selectionLargeEnoughToHaveResizeHandles () const
  598. {
  599. return (selectionResizeHandleAtomicSize () > 0);
  600. }
  601. // public
  602. TQRegion kpView::selectionResizeHandlesViewRegion (bool forRenderer) const
  603. {
  604. TQRegion ret;
  605. const int atomicLength = selectionResizeHandleAtomicSize ();
  606. if (atomicLength <= 0)
  607. return TQRegion ();
  608. // HACK: At low zoom (e.g. 100%), resize handles will probably be too
  609. // big and overlap text / cursor / too much of selection.
  610. //
  611. // So limit the _visual_ size of handles at low zoom. The
  612. // handles' grab area remains the same for usability; so yes,
  613. // there are a few pixels that don't look grabable but they are.
  614. //
  615. // The real solution is to be able to partially render the
  616. // handles outside of the selection view rect. If not possible,
  617. // at least for text boxes, render text on top of handles.
  618. int normalAtomicLength = atomicLength;
  619. int vertEdgeAtomicLength = atomicLength;
  620. if (forRenderer && selection ())
  621. {
  622. if (zoomLevelX () <= 150)
  623. {
  624. if (normalAtomicLength > 1)
  625. normalAtomicLength--;
  626. if (vertEdgeAtomicLength > 1)
  627. vertEdgeAtomicLength--;
  628. }
  629. // 1 line of text?
  630. if (selection ()->isText () && selection ()->textLines ().size () == 1)
  631. {
  632. if (zoomLevelX () <= 150)
  633. vertEdgeAtomicLength = TQMIN (vertEdgeAtomicLength, TQMAX (2, zoomLevelX () / 100));
  634. else if (zoomLevelX () <= 250)
  635. vertEdgeAtomicLength = TQMIN (vertEdgeAtomicLength, TQMAX (3, zoomLevelX () / 100));
  636. }
  637. }
  638. const TQRect selViewRect = selectionViewRect ();
  639. #define ADD_BOX_RELATIVE_TO_SELECTION(type,x,y) \
  640. ret += TQRect ((x), (y), type##AtomicLength, type##AtomicLength)
  641. ADD_BOX_RELATIVE_TO_SELECTION (normal,
  642. selViewRect.width () - normalAtomicLength,
  643. selViewRect.height () - normalAtomicLength);
  644. ADD_BOX_RELATIVE_TO_SELECTION (normal,
  645. selViewRect.width () - normalAtomicLength,
  646. 0);
  647. ADD_BOX_RELATIVE_TO_SELECTION (normal,
  648. 0,
  649. selViewRect.height () - normalAtomicLength);
  650. ADD_BOX_RELATIVE_TO_SELECTION (normal,
  651. 0,
  652. 0);
  653. ADD_BOX_RELATIVE_TO_SELECTION (vertEdge,
  654. selViewRect.width () - vertEdgeAtomicLength,
  655. (selViewRect.height () - vertEdgeAtomicLength) / 2);
  656. ADD_BOX_RELATIVE_TO_SELECTION (normal,
  657. (selViewRect.width () - normalAtomicLength) / 2,
  658. selViewRect.height () - normalAtomicLength);
  659. ADD_BOX_RELATIVE_TO_SELECTION (normal,
  660. (selViewRect.width () - normalAtomicLength) / 2,
  661. 0);
  662. ADD_BOX_RELATIVE_TO_SELECTION (vertEdge,
  663. 0,
  664. (selViewRect.height () - vertEdgeAtomicLength) / 2);
  665. #undef ADD_BOX_RELATIVE_TO_SELECTION
  666. ret.translate (selViewRect.x (), selViewRect.y ());
  667. ret = ret.intersect (selViewRect);
  668. return ret;
  669. }
  670. // public
  671. int kpView::mouseOnSelectionResizeHandle (const TQPoint &viewPoint) const
  672. {
  673. #if DEBUG_KP_VIEW
  674. kdDebug () << "kpView::mouseOnSelectionResizeHandle(viewPoint="
  675. << viewPoint << ")" << endl;
  676. #endif
  677. if (!mouseOnSelection (viewPoint))
  678. {
  679. #if DEBUG_KP_VIEW
  680. kdDebug () << "\tmouse not on sel" << endl;
  681. #endif
  682. return 0;
  683. }
  684. const TQRect selViewRect = selectionViewRect ();
  685. #if DEBUG_KP_VIEW
  686. kdDebug () << "\tselViewRect=" << selViewRect << endl;
  687. #endif
  688. const int atomicLength = selectionResizeHandleAtomicSize ();
  689. #if DEBUG_KP_VIEW
  690. kdDebug () << "\tatomicLength=" << atomicLength << endl;
  691. #endif
  692. if (atomicLength <= 0)
  693. {
  694. #if DEBUG_KP_VIEW
  695. kdDebug () << "\tsel not large enough to have resize handles" << endl;
  696. #endif
  697. // Want to make it possible to move a small selection
  698. return 0;
  699. }
  700. const TQPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint);
  701. #if DEBUG_KP_VIEW
  702. kdDebug () << "\tviewPointRelSel=" << viewPointRelSel << endl;
  703. #endif
  704. #define LOCAL_POINT_IN_BOX_AT(x,y) \
  705. TQRect ((x), (y), atomicLength, atomicLength).contains (viewPointRelSel)
  706. // Favour the bottom & right and the corners.
  707. if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength,
  708. selViewRect.height () - atomicLength))
  709. {
  710. return Bottom | Right;
  711. }
  712. else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, 0))
  713. {
  714. return Top | Right;
  715. }
  716. else if (LOCAL_POINT_IN_BOX_AT (0, selViewRect.height () - atomicLength))
  717. {
  718. return Bottom | Left;
  719. }
  720. else if (LOCAL_POINT_IN_BOX_AT (0, 0))
  721. {
  722. return Top | Left;
  723. }
  724. else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength,
  725. (selViewRect.height () - atomicLength) / 2))
  726. {
  727. return Right;
  728. }
  729. else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2,
  730. selViewRect.height () - atomicLength))
  731. {
  732. return Bottom;
  733. }
  734. else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2, 0))
  735. {
  736. return Top;
  737. }
  738. else if (LOCAL_POINT_IN_BOX_AT (0, (selViewRect.height () - atomicLength) / 2))
  739. {
  740. return Left;
  741. }
  742. else
  743. {
  744. #if DEBUG_KP_VIEW
  745. kdDebug () << "\tnot on sel resize handle" << endl;
  746. #endif
  747. return 0;
  748. }
  749. #undef LOCAL_POINT_IN_BOX_AT
  750. }
  751. // public
  752. bool kpView::mouseOnSelectionToSelectText (const TQPoint &viewPoint) const
  753. {
  754. #if DEBUG_KP_VIEW
  755. kdDebug () << "kpView::mouseOnSelectionToSelectText(viewPoint="
  756. << viewPoint << ")" << endl;
  757. #endif
  758. if (!mouseOnSelection (viewPoint))
  759. {
  760. #if DEBUG_KP_VIEW
  761. kdDebug () << "\tmouse non on sel" << endl;
  762. #endif
  763. return false;
  764. }
  765. if (!selection ()->isText ())
  766. {
  767. #if DEBUG_KP_VIEW
  768. kdDebug () << "\tsel not text" << endl;
  769. #endif
  770. return false;
  771. }
  772. #if DEBUG_KP_VIEW
  773. kdDebug () << "\tmouse on sel: to move=" << mouseOnSelectionToMove ()
  774. << " to resize=" << mouseOnSelectionResizeHandle ()
  775. << endl;
  776. #endif
  777. return (!mouseOnSelectionToMove (viewPoint) &&
  778. !mouseOnSelectionResizeHandle (viewPoint));
  779. }
  780. // protected virtual [base TQWidget]
  781. void kpView::mouseMoveEvent (TQMouseEvent *e)
  782. {
  783. #if DEBUG_KP_VIEW && 0
  784. kdDebug () << "kpView(" << name () << ")::mouseMoveEvent ("
  785. << e->x () << "," << e->y () << ")"
  786. << endl;
  787. #endif
  788. // TODO: This is wrong if you leaveEvent the mainView by mouseMoving on the
  789. // mainView, landing on top of the thumbnailView cleverly put on top
  790. // of the mainView.
  791. setHasMouse (TQT_TQRECT_OBJECT(rect ()).contains (e->pos ()));
  792. if (tool ())
  793. tool ()->mouseMoveEvent (e);
  794. e->accept ();
  795. }
  796. // protected virtual [base TQWidget]
  797. void kpView::mousePressEvent (TQMouseEvent *e)
  798. {
  799. #if DEBUG_KP_VIEW && 0
  800. kdDebug () << "kpView(" << name () << ")::mousePressEvent ("
  801. << e->x () << "," << e->y () << ")"
  802. << endl;
  803. #endif
  804. setHasMouse (true);
  805. if (tool ())
  806. tool ()->mousePressEvent (e);
  807. e->accept ();
  808. }
  809. // protected virtual [base TQWidget]
  810. void kpView::mouseReleaseEvent (TQMouseEvent *e)
  811. {
  812. #if DEBUG_KP_VIEW && 0
  813. kdDebug () << "kpView(" << name () << ")::mouseReleaseEvent ("
  814. << e->x () << "," << e->y () << ")"
  815. << endl;
  816. #endif
  817. setHasMouse (TQT_TQRECT_OBJECT(rect ()).contains (e->pos ()));
  818. if (tool ())
  819. tool ()->mouseReleaseEvent (e);
  820. e->accept ();
  821. }
  822. // public virtual [base TQWidget]
  823. void kpView::wheelEvent (TQWheelEvent *e)
  824. {
  825. if (tool ())
  826. tool ()->wheelEvent (e);
  827. }
  828. // protected virtual [base TQWidget]
  829. void kpView::keyPressEvent (TQKeyEvent *e)
  830. {
  831. #if DEBUG_KP_VIEW && 0
  832. kdDebug () << "kpView(" << name () << ")::keyPressEvent()" << endl;
  833. #endif
  834. if (tool ())
  835. tool ()->keyPressEvent (e);
  836. e->accept ();
  837. }
  838. // protected virtual [base TQWidget]
  839. void kpView::keyReleaseEvent (TQKeyEvent *e)
  840. {
  841. #if DEBUG_KP_VIEW && 0
  842. kdDebug () << "kpView(" << name () << ")::keyReleaseEvent()" << endl;
  843. #endif
  844. if (tool ())
  845. tool ()->keyReleaseEvent (e);
  846. e->accept ();
  847. }
  848. // protected virtual [base TQWidget]
  849. void kpView::focusInEvent (TQFocusEvent *e)
  850. {
  851. #if DEBUG_KP_VIEW && 0
  852. kdDebug () << "kpView(" << name () << ")::focusInEvent()" << endl;
  853. #endif
  854. if (tool ())
  855. tool ()->focusInEvent (e);
  856. }
  857. // protected virtual [base TQWidget]
  858. void kpView::focusOutEvent (TQFocusEvent *e)
  859. {
  860. #if DEBUG_KP_VIEW && 0
  861. kdDebug () << "kpView(" << name () << ")::focusOutEvent()" << endl;
  862. #endif
  863. if (tool ())
  864. tool ()->focusOutEvent (e);
  865. }
  866. // protected virtual [base TQWidget]
  867. void kpView::enterEvent (TQEvent *e)
  868. {
  869. #if DEBUG_KP_VIEW && 0
  870. kdDebug () << "kpView(" << name () << ")::enterEvent()" << endl;
  871. #endif
  872. // Don't call setHasMouse(true) as it displays the brush cursor (if
  873. // active) when dragging open a menu and then dragging
  874. // past the extents of the menu due to TQt sending us an EnterEvent.
  875. // We're already covered by MouseMoveEvent anyway.
  876. //
  877. // But disabling this causes a more serious problem: RMB on a text
  878. // box and Esc. We have no other reliable way to determine if the
  879. // mouse is still above the view (user could have moved mouse out
  880. // while RMB menu was up) and hence the cursor is not updated.
  881. setHasMouse (true);
  882. if (tool ())
  883. tool ()->enterEvent (e);
  884. }
  885. // protected virtual [base TQWidget]
  886. void kpView::leaveEvent (TQEvent *e)
  887. {
  888. #if DEBUG_KP_VIEW && 0
  889. kdDebug () << "kpView(" << name () << ")::leaveEvent()" << endl;
  890. #endif
  891. setHasMouse (false);
  892. if (tool ())
  893. tool ()->leaveEvent (e);
  894. }
  895. // protected virtual [base TQWidget]
  896. void kpView::dragEnterEvent (TQDragEnterEvent *)
  897. {
  898. #if DEBUG_KP_VIEW && 1
  899. kdDebug () << "kpView(" << name () << ")::dragEnterEvent()" << endl;
  900. #endif
  901. setHasMouse (true);
  902. }
  903. // protected virtual [base TQWidget]
  904. void kpView::dragLeaveEvent (TQDragLeaveEvent *)
  905. {
  906. #if DEBUG_KP_VIEW && 1
  907. kdDebug () << "kpView(" << name () << ")::dragLeaveEvent" << endl;
  908. #endif
  909. setHasMouse (false);
  910. }
  911. // public virtual [base TQWidget]
  912. void kpView::resize (int w, int h)
  913. {
  914. #if DEBUG_KP_VIEW && 1
  915. kdDebug () << "kpView(" << name ()
  916. << ")::resize(" << w << "," << h << ")"
  917. << endl;
  918. #endif
  919. TQWidget::resize (w, h);
  920. }
  921. // protected virtual [base TQWidget]
  922. void kpView::resizeEvent (TQResizeEvent *e)
  923. {
  924. #if DEBUG_KP_VIEW && 1
  925. kdDebug () << "kpView(" << name () << ")::resizeEvent("
  926. << e->size ()
  927. << " vs actual=" << size ()
  928. << ") old=" << e->oldSize () << endl;
  929. #endif
  930. TQWidget::resizeEvent (e);
  931. emit sizeChanged (width (), height ());
  932. emit sizeChanged (size ());
  933. }
  934. // private virtual
  935. void kpView::imStartEvent (TQIMEvent *e)
  936. {
  937. #if DEBUG_KP_VIEW && 1
  938. kdDebug () << "kpView(" << name () << ")::imStartEvent" << endl;
  939. #endif
  940. if (tool ())
  941. tool ()->imStartEvent (e);
  942. e->accept();
  943. }
  944. // private virtual
  945. void kpView::imComposeEvent (TQIMEvent *e)
  946. {
  947. #if DEBUG_KP_VIEW && 1
  948. kdDebug () << "kpView(" << name () << ")::imComposeEvent" << endl;
  949. #endif
  950. if (tool ())
  951. tool ()->imComposeEvent (e);
  952. e->accept();
  953. }
  954. // private virtual
  955. void kpView::imEndEvent (TQIMEvent *e)
  956. {
  957. #if DEBUG_KP_VIEW && 1
  958. kdDebug () << "kpView(" << name () << ")::imEndEvent" << endl;
  959. #endif
  960. if (tool ())
  961. tool ()->imEndEvent (e);
  962. e->accept();
  963. }
  964. //
  965. // Renderer
  966. //
  967. // protected
  968. TQRect kpView::paintEventGetDocRect (const TQRect &viewRect) const
  969. {
  970. #if DEBUG_KP_VIEW_RENDERER && 1
  971. kdDebug () << "kpView::paintEventGetDocRect(" << viewRect << ")" << endl;
  972. #endif
  973. TQRect docRect;
  974. // From the "we aren't sure whether to round up or round down" department:
  975. if (zoomLevelX () < 100 || zoomLevelY () < 100)
  976. docRect = transformViewToDoc (viewRect);
  977. else
  978. {
  979. // think of a grid - you need to fully cover the zoomed-in pixels
  980. // when docRect is zoomed back to the view later
  981. docRect = TQRect (transformViewToDoc (viewRect.topLeft ()), // round down
  982. transformViewToDoc (viewRect.bottomRight ())); // round down
  983. }
  984. if (zoomLevelX () % 100 || zoomLevelY () % 100)
  985. {
  986. // at least round up the bottom-right point and deal with matrix weirdness:
  987. // - helpful because it ensures we at least cover the required area
  988. // at e.g. 67% or 573%
  989. // - harmless since paintEventDrawRect() clips for us anyway
  990. docRect.setBottomRight (docRect.bottomRight () + TQPoint (2, 2));
  991. }
  992. #if DEBUG_KP_VIEW_RENDERER && 1
  993. kdDebug () << "\tdocRect=" << docRect << endl;
  994. #endif
  995. kpDocument *doc = document ();
  996. if (doc)
  997. {
  998. docRect = docRect.intersect (doc->rect ());
  999. #if DEBUG_KP_VIEW_RENDERER && 1
  1000. kdDebug () << "\tintersect with doc=" << docRect << endl;
  1001. #endif
  1002. }
  1003. return docRect;
  1004. }
  1005. // public
  1006. void kpView::drawTransparentBackground (TQPainter *painter,
  1007. int /*viewWidth*/, int /*viewHeight*/,
  1008. const TQRect &rect,
  1009. bool isPreview)
  1010. {
  1011. const int cellSize = !isPreview ? 16 : 10;
  1012. int starty = rect.y ();
  1013. if (starty % cellSize)
  1014. starty -= (starty % cellSize);
  1015. int startx = rect.x ();
  1016. if (startx % cellSize)
  1017. startx -= (startx % cellSize);
  1018. painter->save ();
  1019. for (int y = starty; y <= rect.bottom (); y += cellSize)
  1020. {
  1021. for (int x = startx; x <= rect.right (); x += cellSize)
  1022. {
  1023. bool parity = (x / cellSize + y / cellSize) % 2;
  1024. TQColor col;
  1025. if (parity)
  1026. {
  1027. if (!isPreview)
  1028. col = TQColor (213, 213, 213);
  1029. else
  1030. col = TQColor (224, 224, 224);
  1031. }
  1032. else
  1033. col = TQt::white;
  1034. painter->fillRect (x - rect.x (), y - rect.y (), cellSize, cellSize,
  1035. col);
  1036. }
  1037. }
  1038. painter->restore ();
  1039. }
  1040. // protected
  1041. void kpView::paintEventDrawCheckerBoard (TQPainter *painter, const TQRect &viewRect)
  1042. {
  1043. kpDocument *doc = document ();
  1044. if (!doc)
  1045. return;
  1046. drawTransparentBackground (painter,
  1047. doc->width () * zoomLevelX () / 100,
  1048. doc->height () * zoomLevelY () / 100,
  1049. viewRect);
  1050. }
  1051. // protected
  1052. void kpView::paintEventDrawSelection (TQPixmap *destPixmap, const TQRect &docRect)
  1053. {
  1054. #if DEBUG_KP_VIEW_RENDERER && 1
  1055. kdDebug () << "kpView::paintEventDrawSelection() docRect=" << docRect << endl;
  1056. #endif
  1057. kpDocument *doc = document ();
  1058. if (!doc)
  1059. {
  1060. #if DEBUG_KP_VIEW_RENDERER && 1
  1061. kdDebug () << "\tno doc - abort" << endl;
  1062. #endif
  1063. return;
  1064. }
  1065. kpSelection *sel = doc->selection ();
  1066. if (!sel)
  1067. {
  1068. #if DEBUG_KP_VIEW_RENDERER && 1
  1069. kdDebug () << "\tno sel - abort" << endl;
  1070. #endif
  1071. return;
  1072. }
  1073. //
  1074. // Draw selection pixmap (if there is one)
  1075. //
  1076. #if DEBUG_KP_VIEW_RENDERER && 1
  1077. kdDebug () << "\tdraw sel pixmap @ " << sel->topLeft () << endl;
  1078. #endif
  1079. sel->paint (destPixmap, docRect);
  1080. //
  1081. // Draw selection border
  1082. //
  1083. kpViewManager *vm = viewManager ();
  1084. #if DEBUG_KP_VIEW_RENDERER && 1
  1085. kdDebug () << "\tsel border visible="
  1086. << vm->selectionBorderVisible ()
  1087. << endl;
  1088. #endif
  1089. if (vm->selectionBorderVisible ())
  1090. {
  1091. TQPainter destPixmapPainter (destPixmap);
  1092. destPixmapPainter.setRasterOp (TQt::XorROP);
  1093. destPixmapPainter.setPen (TQPen (TQt::white, 1, TQt::DotLine));
  1094. destPixmapPainter.setBackgroundMode (Qt::OpaqueMode);
  1095. destPixmapPainter.setBackgroundColor (TQt::blue);
  1096. TQBitmap maskBitmap;
  1097. TQPainter maskBitmapPainter;
  1098. if (destPixmap->mask ())
  1099. {
  1100. maskBitmap = *destPixmap->mask ();
  1101. maskBitmapPainter.begin (&maskBitmap);
  1102. maskBitmapPainter.setPen (TQt::color1/*opaque*/);
  1103. }
  1104. #define PAINTER_CMD(cmd) \
  1105. { \
  1106. destPixmapPainter . cmd; \
  1107. if (maskBitmapPainter.isActive ()) \
  1108. maskBitmapPainter . cmd; \
  1109. }
  1110. TQRect boundingRect = sel->boundingRect ();
  1111. #if DEBUG_KP_VIEW_RENDERER && 1
  1112. kdDebug () << "\tsel boundingRect="
  1113. << boundingRect
  1114. << endl;
  1115. #endif
  1116. if (boundingRect.topLeft () != boundingRect.bottomRight ())
  1117. {
  1118. switch (sel->type ())
  1119. {
  1120. case kpSelection::Rectangle:
  1121. case kpSelection::Text:
  1122. #if DEBUG_KP_VIEW_RENDERER && 1
  1123. kdDebug () << "\tselection border = rectangle" << endl;
  1124. kdDebug () << "\t\tx=" << boundingRect.x () - docRect.x ()
  1125. << " y=" << boundingRect.y () - docRect.y ()
  1126. << " w=" << boundingRect.width ()
  1127. << " h=" << boundingRect.height ()
  1128. << endl;
  1129. #endif
  1130. PAINTER_CMD (drawRect (boundingRect.x () - docRect.x (),
  1131. boundingRect.y () - docRect.y (),
  1132. boundingRect.width (),
  1133. boundingRect.height ()));
  1134. break;
  1135. case kpSelection::Ellipse:
  1136. #if DEBUG_KP_VIEW_RENDERER && 1
  1137. kdDebug () << "\tselection border = ellipse" << endl;
  1138. #endif
  1139. PAINTER_CMD (drawEllipse (boundingRect.x () - docRect.x (),
  1140. boundingRect.y () - docRect.y (),
  1141. boundingRect.width (),
  1142. boundingRect.height ()));
  1143. break;
  1144. case kpSelection::Points:
  1145. {
  1146. #if DEBUG_KP_VIEW_RENDERER
  1147. kdDebug () << "\tselection border = freeForm" << endl;
  1148. #endif
  1149. TQPointArray points = sel->points ();
  1150. points.detach ();
  1151. points.translate (-docRect.x (), -docRect.y ());
  1152. if (vm->selectionBorderFinished ())
  1153. {
  1154. PAINTER_CMD (drawPolygon (points));
  1155. }
  1156. else
  1157. {
  1158. PAINTER_CMD (drawPolyline (points));
  1159. }
  1160. break;
  1161. }
  1162. default:
  1163. kdError () << "kpView::paintEventDrawSelection() unknown sel border type" << endl;
  1164. break;
  1165. }
  1166. if (vm->selectionBorderFinished () &&
  1167. (sel->type () == kpSelection::Ellipse ||
  1168. sel->type () == kpSelection::Points))
  1169. {
  1170. destPixmapPainter.save ();
  1171. destPixmapPainter.setRasterOp (TQt::NotROP);
  1172. PAINTER_CMD (drawRect (boundingRect.x () - docRect.x (),
  1173. boundingRect.y () - docRect.y (),
  1174. boundingRect.width (),
  1175. boundingRect.height ()));
  1176. destPixmapPainter.restore ();
  1177. }
  1178. }
  1179. else
  1180. {
  1181. // SYNC: Work around TQt bug: can't draw 1x1 rectangle
  1182. PAINTER_CMD (drawPoint (boundingRect.topLeft () - docRect.topLeft ()));
  1183. }
  1184. #undef PAINTER_CMD
  1185. destPixmapPainter.end ();
  1186. if (maskBitmapPainter.isActive ())
  1187. maskBitmapPainter.end ();
  1188. destPixmap->setMask (maskBitmap);
  1189. }
  1190. //
  1191. // Draw text cursor
  1192. //
  1193. if (sel->isText () &&
  1194. vm->textCursorEnabled () &&
  1195. (vm->textCursorBlinkState () ||
  1196. // For the current main window:
  1197. // As long as _any_ view has focus, blink _all_ views not just the
  1198. // one with focus // !this->isActiveWindow ()
  1199. !vm->activeView ())) // sync: call will break when vm is not held by 1 mainWindow
  1200. {
  1201. // TODO: Fix code duplication: kpViewManager::{setTextCursorPosition,updateTextCursor}() & kpView::paintEventDrawSelection()
  1202. TQPoint topLeft = sel->pointForTextRowCol (vm->textCursorRow (), vm->textCursorCol ());
  1203. if (topLeft != KP_INVALID_POINT)
  1204. {
  1205. TQRect rect = TQRect (topLeft.x (), topLeft.y (),
  1206. 1, sel->textStyle ().fontMetrics ().height ());
  1207. rect = rect.intersect (sel->textAreaRect ());
  1208. if (!rect.isEmpty ())
  1209. {
  1210. rect.moveBy (-docRect.x (), -docRect.y ());
  1211. TQBitmap maskBitmap;
  1212. TQPainter destPixmapPainter, maskBitmapPainter;
  1213. if (destPixmap->mask ())
  1214. {
  1215. maskBitmap = *destPixmap->mask ();
  1216. maskBitmapPainter.begin (&maskBitmap);
  1217. maskBitmapPainter.fillRect (rect, TQt::color1/*opaque*/);
  1218. maskBitmapPainter.end ();
  1219. }
  1220. destPixmapPainter.begin (destPixmap);
  1221. destPixmapPainter.setRasterOp (TQt::XorROP);
  1222. destPixmapPainter.fillRect (rect, TQt::white);
  1223. destPixmapPainter.end ();
  1224. if (!maskBitmap.isNull ())
  1225. destPixmap->setMask (maskBitmap);
  1226. }
  1227. }
  1228. }
  1229. }
  1230. // protected
  1231. bool kpView::selectionResizeHandleAtomicSizeCloseToZoomLevel () const
  1232. {
  1233. return (abs (selectionResizeHandleAtomicSize () - zoomLevelX () / 100) < 3);
  1234. }
  1235. // protected
  1236. void kpView::paintEventDrawSelectionResizeHandles (TQPainter *painter, const TQRect &viewRect)
  1237. {
  1238. #if DEBUG_KP_VIEW_RENDERER && 1
  1239. kdDebug () << "kpView::paintEventDrawSelectionResizeHandles("
  1240. << viewRect << ")" << endl;
  1241. #endif
  1242. if (!selectionLargeEnoughToHaveResizeHandles ())
  1243. {
  1244. #if DEBUG_KP_VIEW_RENDERER && 1
  1245. kdDebug () << "\tsel not large enough to have resize handles" << endl;
  1246. #endif
  1247. return;
  1248. }
  1249. kpViewManager *vm = viewManager ();
  1250. if (!vm || !vm->selectionBorderVisible () || !vm->selectionBorderFinished ())
  1251. {
  1252. #if DEBUG_KP_VIEW_RENDERER && 1
  1253. kdDebug () << "\tsel border not visible or not finished" << endl;
  1254. #endif
  1255. return;
  1256. }
  1257. const TQRect selViewRect = selectionViewRect ();
  1258. #if DEBUG_KP_VIEW_RENDERER && 1
  1259. kdDebug () << "\tselViewRect=" << selViewRect << endl;
  1260. #endif
  1261. if (!selViewRect.intersects (viewRect))
  1262. {
  1263. #if DEBUG_KP_VIEW_RENDERER && 1
  1264. kdDebug () << "\tdoesn't intersect viewRect" << endl;
  1265. #endif
  1266. return;
  1267. }
  1268. TQRegion selResizeHandlesRegion = selectionResizeHandlesViewRegion (true/*for renderer*/);
  1269. #if DEBUG_KP_VIEW_RENDERER && 1
  1270. kdDebug () << "\tsel resize handles view region="
  1271. << selResizeHandlesRegion << endl;
  1272. #endif
  1273. selResizeHandlesRegion.translate (-viewRect.x (), -viewRect.y ());
  1274. painter->save ();
  1275. TQColor fillColor;
  1276. if (selectionResizeHandleAtomicSizeCloseToZoomLevel ())
  1277. {
  1278. fillColor = TQt::blue;
  1279. painter->setRasterOp (TQt::CopyROP);
  1280. }
  1281. else
  1282. {
  1283. fillColor = TQt::white;
  1284. painter->setRasterOp (TQt::XorROP);
  1285. }
  1286. TQMemArray <TQRect> rects = selResizeHandlesRegion.rects ();
  1287. for (TQMemArray <TQRect>::ConstIterator it = rects.begin ();
  1288. it != rects.end ();
  1289. it++)
  1290. {
  1291. painter->fillRect (*it, fillColor);
  1292. }
  1293. painter->restore ();
  1294. }
  1295. // protected
  1296. void kpView::paintEventDrawTempPixmap (TQPixmap *destPixmap, const TQRect &docRect)
  1297. {
  1298. kpViewManager *vm = viewManager ();
  1299. if (!vm)
  1300. return;
  1301. const kpTempPixmap *tpm = vm->tempPixmap ();
  1302. #if DEBUG_KP_VIEW_RENDERER && 1
  1303. kdDebug () << "kpView::paintEventDrawTempPixmap() tempPixmap="
  1304. << tpm
  1305. << " isVisible="
  1306. << (tpm ? tpm->isVisible (vm) : false)
  1307. << endl;
  1308. #endif
  1309. if (!tpm || !tpm->isVisible (vm))
  1310. return;
  1311. tpm->paint (destPixmap, docRect);
  1312. }
  1313. // protected
  1314. void kpView::paintEventDrawGridLines (TQPainter *painter, const TQRect &viewRect)
  1315. {
  1316. int hzoomMultiple = zoomLevelX () / 100;
  1317. int vzoomMultiple = zoomLevelY () / 100;
  1318. TQPen ordinaryPen (TQt::gray);
  1319. TQPen tileBoundaryPen (TQt::lightGray);
  1320. painter->setPen (ordinaryPen);
  1321. // horizontal lines
  1322. int starty = viewRect.top ();
  1323. if (starty % vzoomMultiple)
  1324. starty = (starty + vzoomMultiple) / vzoomMultiple * vzoomMultiple;
  1325. int tileHeight = 16 * vzoomMultiple; // CONFIG
  1326. for (int y = starty - viewRect.y (); y <= viewRect.bottom () - viewRect.y (); y += vzoomMultiple)
  1327. {
  1328. if (0 && tileHeight > 0 && y % tileHeight == 0)
  1329. {
  1330. painter->setPen (tileBoundaryPen);
  1331. //painter.setRasterOp (TQt::XorROP);
  1332. }
  1333. painter->drawLine (0, y, viewRect.right () - viewRect.left (), y);
  1334. if (0 && tileHeight > 0 && y % tileHeight == 0)
  1335. {
  1336. painter->setPen (ordinaryPen);
  1337. //painter.setRasterOp (TQt::CopyROP);
  1338. }
  1339. }
  1340. // vertical lines
  1341. int startx = viewRect.left ();
  1342. if (startx % hzoomMultiple)
  1343. startx = (startx + hzoomMultiple) / hzoomMultiple * hzoomMultiple;
  1344. int tileWidth = 16 * hzoomMultiple; // CONFIG
  1345. for (int x = startx - viewRect.x (); x <= viewRect.right () - viewRect.x (); x += hzoomMultiple)
  1346. {
  1347. if (0 && tileWidth > 0 && x % tileWidth == 0)
  1348. {
  1349. painter->setPen (tileBoundaryPen);
  1350. //painter.setRasterOp (TQt::XorROP);
  1351. }
  1352. painter->drawLine (x, 0, x, viewRect.bottom () - viewRect.top ());
  1353. if (0 && tileWidth > 0 && x % tileWidth == 0)
  1354. {
  1355. painter->setPen (ordinaryPen);
  1356. //painter.setRasterOp (TQt::CopyROP);
  1357. }
  1358. }
  1359. }
  1360. void kpView::paintEventDrawRect (const TQRect &viewRect)
  1361. {
  1362. #if DEBUG_KP_VIEW_RENDERER
  1363. kdDebug () << "\tkpView::paintEventDrawRect(viewRect=" << viewRect
  1364. << ")" << endl;
  1365. #endif
  1366. kpViewManager *vm = viewManager ();
  1367. const kpDocument *doc = document ();
  1368. if (!vm || !doc)
  1369. return;
  1370. if (viewRect.isEmpty ())
  1371. return;
  1372. TQRect docRect = paintEventGetDocRect (viewRect);
  1373. #if DEBUG_KP_VIEW_RENDERER && 1
  1374. kdDebug () << "\tdocRect=" << docRect << endl;
  1375. #endif
  1376. // uncomment to cause deliberate flicker (identifies needless updates)
  1377. #if DEBUG_KP_VIEW_RENDERER && 0
  1378. TQPainter flickerPainter (this);
  1379. flickerPainter.fillRect (viewRect, TQt::red);
  1380. flickerPainter.end ();
  1381. #endif
  1382. //
  1383. // Prepare Back Buffer
  1384. //
  1385. if (!d->m_backBuffer ||
  1386. d->m_backBuffer->width () < viewRect.width () ||
  1387. d->m_backBuffer->height () < viewRect.height () ||
  1388. d->m_backBuffer->width () > width () ||
  1389. d->m_backBuffer->height () > height ())
  1390. {
  1391. // don't use TQPixmap::resize() as that wastes time copying pixels
  1392. // that will be overwritten anyway
  1393. //
  1394. // OPT: Should use doubling trick or at least go up in multiples
  1395. // to reduce X server pressure.
  1396. delete d->m_backBuffer;
  1397. d->m_backBuffer = new TQPixmap (viewRect.width (), viewRect.height ());
  1398. }
  1399. // uncomment to catch bits of the view that the renderer forgot to update
  1400. #if 0
  1401. d->m_backBuffer->fill (TQt::green);
  1402. #endif
  1403. TQPainter backBufferPainter;
  1404. backBufferPainter.begin (d->m_backBuffer);
  1405. //
  1406. // Draw checkboard for transparent images and/or views with borders
  1407. //
  1408. TQPixmap docPixmap;
  1409. bool tempPixmapWillBeRendered = false;
  1410. if (!docRect.isEmpty ())
  1411. {
  1412. docPixmap = doc->getPixmapAt (docRect);
  1413. tempPixmapWillBeRendered =
  1414. (!doc->selection () &&
  1415. vm->tempPixmap () &&
  1416. vm->tempPixmap ()->isVisible (vm) &&
  1417. docRect.intersects (vm->tempPixmap ()->rect ()));
  1418. #if DEBUG_KP_VIEW_RENDERER && 1
  1419. kdDebug () << "\ttempPixmapWillBeRendered=" << tempPixmapWillBeRendered
  1420. << " (sel=" << doc->selection ()
  1421. << " tempPixmap=" << vm->tempPixmap ()
  1422. << " tempPixmap.isVisible=" << (vm->tempPixmap () ? vm->tempPixmap ()->isVisible (vm) : false)
  1423. << " docRect.intersects(tempPixmap.rect)=" << (vm->tempPixmap () ? docRect.intersects (vm->tempPixmap ()->rect ()) : false)
  1424. << ")"
  1425. << endl;
  1426. #endif
  1427. }
  1428. if (docPixmap.mask () ||
  1429. (tempPixmapWillBeRendered && vm->tempPixmap ()->mayChangeDocumentMask ()))
  1430. {
  1431. #if DEBUG_KP_VIEW_RENDERER && 1
  1432. kdDebug () << "\tmask=" << (bool) docPixmap.mask ()
  1433. << endl;
  1434. #endif
  1435. paintEventDrawCheckerBoard (&backBufferPainter, viewRect);
  1436. }
  1437. else
  1438. {
  1439. #if DEBUG_KP_VIEW_RENDERER && 1
  1440. kdDebug () << "\tno mask" << endl;
  1441. #endif
  1442. }
  1443. if (!docRect.isEmpty ())
  1444. {
  1445. //
  1446. // Draw docPixmap + tempPixmap
  1447. //
  1448. if (doc->selection ())
  1449. {
  1450. paintEventDrawSelection (&docPixmap, docRect);
  1451. }
  1452. else if (tempPixmapWillBeRendered)
  1453. {
  1454. paintEventDrawTempPixmap (&docPixmap, docRect);
  1455. }
  1456. #if DEBUG_KP_VIEW_RENDERER && 1
  1457. kdDebug () << "\torigin=" << origin () << endl;
  1458. #endif
  1459. // blit scaled version of docPixmap + tempPixmap onto Back Buffer
  1460. #if DEBUG_KP_VIEW_RENDERER && 1
  1461. TQTime scaleTimer; scaleTimer.start ();
  1462. #endif
  1463. backBufferPainter.translate (origin ().x () - viewRect.x (),
  1464. origin ().y () - viewRect.y ());
  1465. backBufferPainter.scale (double (zoomLevelX ()) / 100.0,
  1466. double (zoomLevelY ()) / 100.0);
  1467. backBufferPainter.drawPixmap (docRect, docPixmap);
  1468. backBufferPainter.resetXForm (); // back to 1-1 scaling
  1469. #if DEBUG_KP_VIEW_RENDERER && 1
  1470. kdDebug () << "\tscale time=" << scaleTimer.elapsed () << endl;
  1471. #endif
  1472. } // if (!docRect.isEmpty ()) {
  1473. //
  1474. // Draw Grid Lines
  1475. //
  1476. if (isGridShown ())
  1477. {
  1478. #if DEBUG_KP_VIEW_RENDERER && 1
  1479. TQTime gridTimer; gridTimer.start ();
  1480. #endif
  1481. paintEventDrawGridLines (&backBufferPainter, viewRect);
  1482. #if DEBUG_KP_VIEW_RENDERER && 1
  1483. kdDebug () << "\tgrid time=" << gridTimer.elapsed () << endl;
  1484. #endif
  1485. }
  1486. const TQRect bvsvRect = buddyViewScrollableContainerRectangle ();
  1487. if (!bvsvRect.isEmpty ())
  1488. {
  1489. backBufferPainter.save ();
  1490. backBufferPainter.setRasterOp (TQt::XorROP);
  1491. backBufferPainter.setPen (TQt::white);
  1492. backBufferPainter.translate (-viewRect.x (), -viewRect.y ());
  1493. backBufferPainter.drawRect (bvsvRect);
  1494. backBufferPainter.restore ();
  1495. }
  1496. if (!docRect.isEmpty ())
  1497. {
  1498. if (doc->selection ())
  1499. {
  1500. // Draw resize handles on top of possible grid lines
  1501. paintEventDrawSelectionResizeHandles (&backBufferPainter, viewRect);
  1502. }
  1503. }
  1504. //
  1505. // Blit Back Buffer to View
  1506. //
  1507. backBufferPainter.end ();
  1508. bitBlt (this, viewRect.topLeft (),
  1509. d->m_backBuffer, TQRect (0, 0, viewRect.width (), viewRect.height ()));
  1510. }
  1511. // protected virtual [base TQWidget]
  1512. void kpView::paintEvent (TQPaintEvent *e)
  1513. {
  1514. // sync: kpViewPrivate
  1515. // WARNING: document(), viewManager() and friends might be 0 in this method.
  1516. // TODO: I'm not 100% convinced that we always check if their friends are 0.
  1517. #if DEBUG_KP_VIEW_RENDERER && 1
  1518. TQTime timer;
  1519. timer.start ();
  1520. #endif
  1521. kpViewManager *vm = viewManager ();
  1522. #if DEBUG_KP_VIEW_RENDERER && 1
  1523. kdDebug () << "kpView(" << name () << ")::paintEvent() vm=" << (bool) vm
  1524. << " queueUpdates=" << (vm && vm->queueUpdates ())
  1525. << " fastUpdates=" << (vm && vm->fastUpdates ())
  1526. << " viewRect=" << e->rect ()
  1527. << " erased=" << e->erased ()
  1528. << " topLeft=" << TQPoint (x (), y ())
  1529. << endl;
  1530. #endif
  1531. if (!vm)
  1532. return;
  1533. if (vm->queueUpdates ())
  1534. {
  1535. // OPT: if this update was due to the document,
  1536. // use document coordinates (in case of a zoom change in
  1537. // which view coordinates become out of date)
  1538. addToQueuedArea (e->region ());
  1539. return;
  1540. }
  1541. TQRegion viewRegion = clipRegion ().intersect (e->region ());
  1542. TQMemArray <TQRect> rects = viewRegion.rects ();
  1543. #if DEBUG_KP_VIEW_RENDERER && 1
  1544. kdDebug () << "\t#rects = " << rects.count () << endl;
  1545. #endif
  1546. for (TQMemArray <TQRect>::ConstIterator it = rects.begin ();
  1547. it != rects.end ();
  1548. it++)
  1549. {
  1550. paintEventDrawRect (*it);
  1551. }
  1552. #if DEBUG_KP_VIEW_RENDERER && 1
  1553. kdDebug () << "\tall done in: " << timer.restart () << "ms" << endl;
  1554. #endif
  1555. }
  1556. #include <kpview.moc>