KoRuler.cpp
1/* This file is part of the KDE project
2 Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20// Description: Ruler (header)
21
22/******************************************************************/
23
24#include "KoRuler.h"
25#include <tdelocale.h>
26#include <tdeglobalsettings.h>
27#include <kdebug.h>
28#include <kiconloader.h>
29#include <tqcursor.h>
30#include <tqpainter.h>
31#include <tqpopupmenu.h>
32#include <tqtooltip.h>
33#include <KoPageLayout.h>
34
35class KoRulerPrivate {
36public:
37 KoRulerPrivate() {
38 }
39 ~KoRulerPrivate() {}
40
41 TQWidget *canvas;
42 int flags;
43 int oldMx, oldMy;
44 bool whileMovingBorderLeft, whileMovingBorderRight;
45 bool whileMovingBorderTop, whileMovingBorderBottom;
46 TQPixmap pmFirst, pmLeft;
47 KoPageLayout layout;
48 KoTabChooser *tabChooser;
49 KoTabulatorList tabList;
50 // Do we have to remove a certain tab in the DC Event?
51 KoTabulator removeTab;
52 // The tab we're moving / clicking on - basically only valid between press and release time
53 KoTabulator currTab;
54 // The action we're currently doing - basically only valid between press and release time
55 KoRuler::Action action;
56 TQPopupMenu *rb_menu;
57 int mRemoveTab, mPageLayout; // menu item ids
58 int frameEnd;
59 double i_right;
60 bool m_bReadWrite;
61 bool doubleClickedIndent;
62 bool rtl;
63 bool mousePressed;
64};
65
66// Equality test for tab positions in particular
67static inline bool equals( double a, double b ) {
68 return kAbs( a - b ) < 1E-4;
69}
70
71
72/******************************************************************/
73/* Class: KoRuler */
74/******************************************************************/
75
76const int KoRuler::F_TABS = 1;
77const int KoRuler::F_INDENTS = 2;
78const int KoRuler::F_HELPLINES = 4;
79const int KoRuler::F_NORESIZE = 8;
80
81/*================================================================*/
82KoRuler::KoRuler( TQWidget *_parent, TQWidget *_canvas, TQt::Orientation _orientation,
83 const KoPageLayout& _layout, int _flags, KoUnit::Unit _unit, KoTabChooser *_tabChooser )
84 : TQFrame( _parent ), buffer( width(), height() ), m_zoom(1.0), m_1_zoom(1.0),
85 m_unit( _unit )
86{
87 setWFlags( WResizeNoErase | WRepaintNoErase );
88 setFrameStyle( MenuBarPanel );
89
90 d=new KoRulerPrivate();
91
92 d->tabChooser = _tabChooser;
93
94 d->canvas = _canvas;
95 orientation = _orientation;
96 d->layout = _layout;
97 d->flags = _flags;
98
99 d->m_bReadWrite=true;
100 d->doubleClickedIndent=false;
101 diffx = 0;
102 diffy = 0;
103 i_left=0.0;
104 i_first=0.0;
105 d->i_right=0.0;
106
107 setMouseTracking( true );
108 d->mousePressed = false;
109 d->action = A_NONE;
110
111 d->oldMx = 0;
112 d->oldMy = 0;
113 d->rtl = false;
114
115 showMPos = false;
116 mposX = 0;
117 mposY = 0;
118 gridSize=0.0;
119 hasToDelete = false;
120 d->whileMovingBorderLeft = d->whileMovingBorderRight = d->whileMovingBorderTop = d->whileMovingBorderBottom = false;
121
122 d->pmFirst = UserIcon( "koRulerFirst" );
123 d->pmLeft = UserIcon( "koRulerLeft" );
124 d->currTab.type = T_INVALID;
125
126 d->removeTab.type = T_INVALID;
127 if ( orientation == TQt::Horizontal ) {
128 frameStart = tqRound( zoomIt(d->layout.ptLeft) );
129 d->frameEnd = tqRound( zoomIt(d->layout.ptWidth - d->layout.ptRight) );
130 } else {
131 frameStart = tqRound( zoomIt(d->layout.ptTop) );
132 d->frameEnd = tqRound( zoomIt(d->layout.ptHeight - d->layout.ptBottom) );
133 }
134 m_bFrameStartSet = false;
135
136 setupMenu();
137
138 // For compatibility, emitting doubleClicked shall emit openPageLayoutDia
139 connect( this, TQ_SIGNAL( doubleClicked() ), this, TQ_SIGNAL( openPageLayoutDia() ) );
140}
141
142/*================================================================*/
143KoRuler::~KoRuler()
144{
145 delete d->rb_menu;
146 delete d;
147}
148
150{
151 d->rb_menu->setItemEnabled(d->mPageLayout, b);
152}
153
154/*================================================================*/
155void KoRuler::setMousePos( int mx, int my )
156{
157 if ( !showMPos || ( mx == mposX && my == mposY ) ) return;
158
159 TQPainter p( this );
160 p.setRasterOp( TQt::NotROP );
161
162 if ( orientation == TQt::Horizontal ) {
163 if ( hasToDelete )
164 p.drawLine( mposX, 1, mposX, height() - 1 );
165 p.drawLine( mx, 1, mx, height() - 1 );
166 hasToDelete = true;
167 }
168 else {
169 if ( hasToDelete )
170 p.drawLine( 1, mposY, width() - 1, mposY );
171 p.drawLine( 1, my, width() - 1, my );
172 hasToDelete = true;
173 }
174 p.end();
175
176 mposX = mx;
177 mposY = my;
178}
179
180// distance between the main lines (those with a number)
181double KoRuler::lineDistance() const
182{
183 switch( m_unit ) {
184 case KoUnit::U_INCH:
185 return INCH_TO_POINT( m_zoom ); // every inch
186 case KoUnit::U_PT:
187 return 100.0 * m_zoom; // every 100 pt
188 case KoUnit::U_MM:
189 case KoUnit::U_CM:
190 case KoUnit::U_DM:
191 return CM_TO_POINT ( m_zoom ); // every cm
192 case KoUnit::U_PI:
193 return PI_TO_POINT ( 10.0 * m_zoom ); // every 10 pica
194 case KoUnit::U_DD:
195 return DD_TO_POINT( m_zoom ); // every diderot
196 case KoUnit::U_CC:
197 return CC_TO_POINT( 10.0 * m_zoom ); // every 10 cicero
198 }
199 // should never end up here
200 return 100.0 * m_zoom;
201}
202
203/*================================================================*/
204void KoRuler::drawHorizontal( TQPainter *_painter )
205{
206 TQFont font = TDEGlobalSettings::toolBarFont();
207 TQFontMetrics fm( font );
208 resize( width(), TQMAX( fm.height() + 4, 20 ) );
209
210 // Use a double-buffer pixmap
211 TQPainter p( &buffer );
212 p.fillRect( 0, 0, width(), height(), TQBrush( colorGroup().brush( TQColorGroup::Background ) ) );
213
214 int totalw = tqRound( zoomIt(d->layout.ptWidth) );
215 TQString str;
216
217 p.setBrush( colorGroup().brush( TQColorGroup::Base ) );
218
219 // Draw white rect
220 TQRect r;
221 if ( !d->whileMovingBorderLeft )
222 r.setLeft( -diffx + frameStart );
223 else
224 r.setLeft( d->oldMx );
225 r.setTop( 0 );
226 if ( !d->whileMovingBorderRight )
227 r.setWidth(d->frameEnd-frameStart);
228 else
229 r.setRight( d->oldMx );
230 r.setBottom( height() );
231
232 p.drawRect( r );
233 p.setFont( font );
234
235 // Draw the numbers
236 double dist = lineDistance();
237 int maxwidth = 0;
238
239 for ( double i = 0.0;i <= (double)totalw;i += dist ) {
240 str = TQString::number( KoUnit::toUserValue( i / m_zoom, m_unit ) );
241 int textwidth = fm.width( str );
242 maxwidth = TQMAX( maxwidth, textwidth );
243 }
244
245 // Make sure that the ruler stays readable at lower zoom levels
246 while( dist <= maxwidth ) {
247 dist += lineDistance();
248 }
249
250 for ( double i = 0.0;i <= (double)totalw;i += dist ) {
251 str = TQString::number( KoUnit::toUserValue( i / m_zoom, m_unit ) );
252 int textwidth = fm.width( str );
253 maxwidth = TQMAX( maxwidth, textwidth );
254 p.drawText( tqRound(i) - diffx - tqRound(textwidth * 0.5),
255 tqRound(( height() - fm.height() ) * 0.5),
256 textwidth, height(), AlignLeft | AlignTop, str );
257 }
258
259 // Draw the medium-sized lines
260 // Only if we have enough space (i.e. not at 33%)
261 if ( dist > maxwidth + 2 )
262 {
263 for ( double i = dist * 0.5;i <= (double)totalw;i += dist ) {
264 int ii=tqRound(i);
265 p.drawLine( ii - diffx, 7, ii - diffx, height() - 7 );
266 }
267 }
268
269 // Draw the small lines
270 // Only if we have enough space (i.e. not at 33%)
271 if ( dist * 0.5 > maxwidth + 2 )
272 {
273 for ( double i = dist * 0.25;i <= (double)totalw;i += dist * 0.5 ) {
274 int ii=tqRound(i);
275 p.drawLine( ii - diffx, 9, ii - diffx, height() - 9 );
276 }
277 }
278
279 // Draw ending bar (at page width)
280 //int constant=zoomIt(1);
281 //p.drawLine( totalw - diffx + constant, 1, totalw - diffx + constant, height() - 1 );
282 //p.setPen( colorGroup().color( TQColorGroup::Base ) );
283 //p.drawLine( totalw - diffx, 1, totalw - diffx, height() - 1 );
284
285 // Draw starting bar (at 0)
286 //p.setPen( colorGroup().color( TQColorGroup::Text ) );
287 //p.drawLine( -diffx, 1, -diffx, height() - 1 );
288 //p.setPen( colorGroup().color( TQColorGroup::Base ) );
289 //p.drawLine( -diffx - constant, 1, -diffx - constant, height() - 1 );
290
291 // Draw the indents triangles
292 if ( d->flags & F_INDENTS ) {
293 int top = 1;
294 double halfPixmapWidth = d->pmFirst.width() * 0.5;
295 // Cumulate i_first with correct indent
296 double firstLineIdent = i_first + ( d->rtl ? d->i_right : i_left );
297 p.drawPixmap( tqRound( static_cast<double>(r.left()) + applyRtlAndZoom( firstLineIdent ) - halfPixmapWidth ),
298 top, d->pmFirst );
299
300 int bottom = height() - d->pmLeft.height() - 1;
301 halfPixmapWidth = d->pmLeft.width() * 0.5;
302 p.drawPixmap( tqRound( static_cast<double>(r.left()) + zoomIt(i_left) - halfPixmapWidth ),
303 bottom, d->pmLeft );
304 p.drawPixmap( tqRound( static_cast<double>(r.right()) - zoomIt(d->i_right) - halfPixmapWidth ),
305 bottom, d->pmLeft );
306 }
307
308 // Show the mouse position
309 if ( d->action == A_NONE && showMPos ) {
310 p.setPen( colorGroup().color( TQColorGroup::Text ) );
311 p.drawLine( mposX, 1, mposX, height() - 1 );
312 }
313 hasToDelete = false;
314
315 // Draw the tabs
316 if ( d->tabChooser && ( d->flags & F_TABS ) && !d->tabList.isEmpty() )
317 drawTabs( p );
318
319 p.end();
320 _painter->drawPixmap( 0, 0, buffer );
321}
322
323/*================================================================*/
324void KoRuler::drawTabs( TQPainter &_painter )
325{
326 int ptPos = 0;
327
328 _painter.setPen( TQPen( colorGroup().color( TQColorGroup::Text ), 2, SolidLine ) );
329 // Check if we're in a mousemove event, removing a tab.
330 // In that case, we'll have to skip drawing that one.
331 bool willRemove = d->mousePressed && willRemoveTab( d->oldMy ) && d->currTab.type != T_INVALID;
332
333 KoTabulatorList::ConstIterator it = d->tabList.begin();
334 for ( ; it != d->tabList.end() ; it++ ) {
335 if ( willRemove && equals( d->currTab.ptPos, (*it).ptPos ) )
336 continue;
337 ptPos = tqRound(applyRtlAndZoom((*it).ptPos)) - diffx + frameStart;
338 switch ( (*it).type ) {
339 case T_LEFT: {
340 ptPos -= 4;
341 _painter.drawLine( ptPos + 4, height() - 4, ptPos + 20 - 4, height() - 4 );
342 _painter.drawLine( ptPos + 5, 4, ptPos + 5, height() - 4 );
343 } break;
344 case T_CENTER: {
345 ptPos -= 10;
346 _painter.drawLine( ptPos + 4, height() - 4, ptPos + 20 - 4, height() - 4 );
347 _painter.drawLine( ptPos + 20 / 2, 4, ptPos + 20 / 2, height() - 4 );
348 } break;
349 case T_RIGHT: {
350 ptPos -= 16;
351 _painter.drawLine( ptPos + 4, height() - 4, ptPos + 20 - 4, height() - 4 );
352 _painter.drawLine( ptPos + 20 - 5, 4, ptPos + 20 - 5, height() - 4 );
353 } break;
354 case T_DEC_PNT: {
355 ptPos -= 10;
356 _painter.drawLine( ptPos + 4, height() - 4, ptPos + 20 - 4, height() - 4 );
357 _painter.drawLine( ptPos + 20 / 2, 4, ptPos + 20 / 2, height() - 4 );
358 _painter.fillRect( ptPos + 20 / 2 + 2, height() - 9, 3, 3,
359 colorGroup().color( TQColorGroup::Text ) );
360 } break;
361 default: break;
362 }
363 }
364}
365
366/*================================================================*/
367void KoRuler::drawVertical( TQPainter *_painter )
368{
369 TQFont font = TDEGlobalSettings::toolBarFont();
370 TQFontMetrics fm( font );
371 resize( TQMAX( fm.height() + 4, 20 ), height() );
372
373 TQPainter p( &buffer );
374 p.fillRect( 0, 0, width(), height(), TQBrush( colorGroup().brush( TQColorGroup::Background ) ) );
375
376 int totalh = tqRound( zoomIt(d->layout.ptHeight) );
377 // Clip rect - this gives basically always a rect like (2,2,width-2,height-2)
378 TQRect paintRect = _painter->clipRegion( TQPainter::CoordPainter ).boundingRect();
379 // Ruler rect
380 TQRect rulerRect( 0, -diffy, width(), totalh );
381
382 if ( paintRect.intersects( rulerRect ) ) {
383 TQString str;
384
385 p.setBrush( colorGroup().brush( TQColorGroup::Base ) );
386
387 // Draw white rect
388 TQRect r;
389 if ( !d->whileMovingBorderTop )
390 r.setTop( -diffy + frameStart );
391 else
392 r.setTop( d->oldMy );
393 r.setLeft( 0 );
394 if ( !d->whileMovingBorderBottom )
395 r.setHeight(d->frameEnd-frameStart);
396 else
397 r.setBottom( d->oldMy );
398 r.setRight( width() );
399
400 p.drawRect( r );
401 p.setFont( font );
402
403 // Draw the numbers
404 double dist = lineDistance();
405 int maxheight = 0;
406
407 for ( double i = 0.0;i <= (double)totalh;i += dist ) {
408 str = TQString::number( KoUnit::toUserValue( i / m_zoom, m_unit ) );
409 int textwidth = fm.width( str );
410 maxheight = TQMAX( maxheight, textwidth );
411 }
412
413 // Make sure that the ruler stays readable at lower zoom levels
414 while( dist <= maxheight ) {
415 dist += lineDistance();
416 }
417
418 for ( double i = 0.0;i <= (double)totalh;i += dist ) {
419 str = TQString::number( KoUnit::toUserValue( i / m_zoom, m_unit ) );
420 int textwidth = fm.width( str );
421 int yOffset = tqRound(i) - diffy + tqRound(textwidth * 0.5);
422 if(yOffset > paintRect.bottom())
423 break; // stop drawing when outside the to-paint-region
424 int textheight = fm.height();
425 maxheight = TQMAX( maxheight, textwidth );
426 p.save();
427 p.translate( tqRound(( width() - textheight ) * 0.5), yOffset);
428 p.rotate( -90 );
429 p.drawText( 0, 0, textwidth + 1, textheight, AlignLeft | AlignTop, str );
430 p.restore();
431 }
432
433 // Draw the medium-sized lines
434 if ( dist > maxheight + 2 )
435 {
436 for ( double i = dist * 0.5;i <= (double)totalh;i += dist ) {
437 int ii=tqRound(i) - diffy;
438 if(ii > paintRect.bottom())
439 break; // stop drawing when outside the to-paint-region
440 p.drawLine( 7, ii, width() - 7, ii);
441 }
442 }
443
444 // Draw the small lines
445 if ( dist * 0.5 > maxheight + 2 )
446 {
447 for ( double i = dist * 0.25;i <=(double)totalh;i += dist *0.5 ) {
448 int ii=tqRound(i) - diffy;
449 if(ii > paintRect.bottom())
450 break; // stop drawing when outside the to-paint-region
451 p.drawLine( 9, ii, width() - 9, ii);
452 }
453 }
454
455 // Draw ending bar (at page height)
456 //p.drawLine( 1, totalh - diffy + 1, width() - 1, totalh - diffy + 1 );
457 //p.setPen( colorGroup().color( TQColorGroup::Base ) );
458 //p.drawLine( 1, totalh - diffy, width() - 1, totalh - diffy );
459
460 // Draw starting bar (at 0)
461 //p.setPen( colorGroup().color( TQColorGroup::Text ) );
462 //p.drawLine( 1, -diffy, width() - 1, -diffy );
463 //p.setPen( colorGroup().color( TQColorGroup::Base ) );
464 //p.drawLine( 1, -diffy - 1, width() - 1, -diffy - 1 );
465 }
466
467 // Show the mouse position
468 if ( d->action == A_NONE && showMPos ) {
469 p.setPen( colorGroup().color( TQColorGroup::Text ) );
470 p.drawLine( 1, mposY, width() - 1, mposY );
471 }
472 hasToDelete = false;
473
474 p.end();
475 _painter->drawPixmap( 0, 0, buffer );
476}
477
478void KoRuler::mousePressEvent( TQMouseEvent *e )
479{
480 if( !d->m_bReadWrite)
481 return;
482
483 d->oldMx = e->x();
484 d->oldMy = e->y();
485 d->mousePressed = true;
486 d->removeTab.type = T_INVALID;
487
488 switch ( e->button() ) {
489 case TQt::RightButton:
490 if(d->currTab.type == T_INVALID || !(d->flags & F_TABS))
491 d->rb_menu->setItemEnabled(d->mRemoveTab, false);
492 else
493 d->rb_menu->setItemEnabled(d->mRemoveTab, true);
494 d->rb_menu->popup( TQCursor::pos() );
495 d->action = A_NONE;
496 d->mousePressed = false;
497 return;
498 case TQt::MidButton:
499 // MMB shall do like double-click (it opens a dialog).
500 handleDoubleClick();
501 return;
502 case TQt::LeftButton:
503 if ( d->action == A_BR_RIGHT || d->action == A_BR_LEFT ) {
504 if ( d->action == A_BR_RIGHT )
505 d->whileMovingBorderRight = true;
506 else
507 d->whileMovingBorderLeft = true;
508
509 if ( d->canvas )
510 drawLine(d->oldMx, -1);
511 update();
512 } else if ( d->action == A_BR_TOP || d->action == A_BR_BOTTOM ) {
513 if ( d->action == A_BR_TOP )
514 d->whileMovingBorderTop = true;
515 else
516 d->whileMovingBorderBottom = true;
517
518 if ( d->canvas ) {
519 TQPainter p( d->canvas );
520 p.setRasterOp( TQt::NotROP );
521 p.drawLine( 0, d->oldMy, d->canvas->width(), d->oldMy );
522 p.end();
523 }
524 update();
525 } else if ( d->action == A_FIRST_INDENT || d->action == A_LEFT_INDENT || d->action == A_RIGHT_INDENT ) {
526 if ( d->canvas )
527 drawLine(d->oldMx, -1);
528 } else if ( d->action == A_TAB ) {
529 if ( d->canvas && d->currTab.type != T_INVALID ) {
530 drawLine( tqRound( applyRtlAndZoom(d->currTab.ptPos) ) + frameStart - diffx, -1 );
531 }
532 } else if ( d->tabChooser && ( d->flags & F_TABS ) && d->tabChooser->getCurrTabType() != 0 ) {
533 int left = frameStart - diffx;
534 int right = d->frameEnd - diffx;
535
536 if( e->x()-left < 0 || right-e->x() < 0 )
537 return;
538 KoTabulator tab;
539 tab.filling = TF_BLANK;
540 tab.ptWidth = 0.5;
541 switch ( d->tabChooser->getCurrTabType() ) {
542 case KoTabChooser::TAB_LEFT:
543 tab.type = T_LEFT;
544 break;
545 case KoTabChooser::TAB_CENTER:
546 tab.type = T_CENTER;
547 break;
548 case KoTabChooser::TAB_RIGHT:
549 tab.type = T_RIGHT;
550 break;
551 case KoTabChooser::TAB_DEC_PNT:
552 tab.type = T_DEC_PNT;
553 tab.alignChar = TDEGlobal::locale()->decimalSymbol()[0];
554 break;
555 default: break;
556 }
557 tab.ptPos = unZoomItRtl( e->x() + diffx - frameStart );
558
559 KoTabulatorList::Iterator it=d->tabList.begin();
560 while ( it!=d->tabList.end() && tab > (*it) )
561 ++it;
562
563 d->tabList.insert(it, tab);
564
565 d->action = A_TAB;
566 d->removeTab = tab;
567 d->currTab = tab;
568
569 emit tabListChanged( d->tabList );
570 update();
571 }
572 else if ( d->flags & F_HELPLINES )
573 {
574 setCursor( orientation == TQt::Horizontal ?
575 TQt::sizeVerCursor : TQt::sizeHorCursor );
576 d->action = A_HELPLINES;
577 }
578 default:
579 break;
580 }
581}
582
583void KoRuler::mouseReleaseEvent( TQMouseEvent *e )
584{
585 d->mousePressed = false;
586
587 // Hacky, but necessary to prevent multiple tabs with the same coordinates (Werner)
588 bool fakeMovement=false;
589 if(d->removeTab.type != T_INVALID) {
590 mouseMoveEvent(e);
591 fakeMovement=true;
592 }
593
594 if ( d->action == A_BR_RIGHT || d->action == A_BR_LEFT ) {
595 d->whileMovingBorderRight = false;
596 d->whileMovingBorderLeft = false;
597
598 if ( d->canvas )
599 drawLine(d->oldMx, -1);
600 update();
601 emit newPageLayout( d->layout );
602 } else if ( d->action == A_BR_TOP || d->action == A_BR_BOTTOM ) {
603 d->whileMovingBorderTop = false;
604 d->whileMovingBorderBottom = false;
605
606 if ( d->canvas ) {
607 TQPainter p( d->canvas );
608 p.setRasterOp( TQt::NotROP );
609 p.drawLine( 0, d->oldMy, d->canvas->width(), d->oldMy );
610 p.end();
611 }
612 update();
613 emit newPageLayout( d->layout );
614 } else if ( d->action == A_FIRST_INDENT ) {
615 if ( d->canvas )
616 drawLine(d->oldMx, -1);
617 update();
618 emit newFirstIndent( i_first );
619 } else if ( d->action == A_LEFT_INDENT ) {
620 if ( d->canvas )
621 drawLine(d->oldMx, -1);
622 update();
623 emit newLeftIndent( i_left );
624 } else if ( d->action == A_RIGHT_INDENT ) {
625 if ( d->canvas )
626 drawLine(d->oldMx, -1);
627 update();
628 emit newRightIndent( d->i_right );
629 } else if ( d->action == A_TAB ) {
630 if ( d->canvas && !fakeMovement ) {
631 drawLine( tqRound( applyRtlAndZoom( d->currTab.ptPos ) ) + frameStart - diffx, -1);
632 }
633 if ( willRemoveTab( e->y() ) )
634 {
635 d->tabList.remove(d->currTab);
636 }
637 qHeapSort( d->tabList );
638
639 // Delete the new tabulator if it is placed on top of another.
640 KoTabulatorList::ConstIterator tmpTab=d->tabList.begin();
641 int count=0;
642 while(tmpTab!=d->tabList.end()) {
643 if( equals( (*tmpTab).ptPos, d->currTab.ptPos ) ) {
644 count++;
645 if(count > 1) {
646 d->tabList.remove(d->currTab);
647 break;
648 }
649 }
650 tmpTab++;
651 }
652 //searchTab( e->x() ); // DF: why set currTab here?
653 emit tabListChanged( d->tabList );
654 update();
655 }
656 else if( d->action == A_HELPLINES )
657 {
658 emit addGuide( e->pos(), orientation == TQt::Horizontal, orientation == TQt::Horizontal ? size().height() : size().width() );
659 emit addHelpline( e->pos(), orientation == TQt::Horizontal);
660 setCursor( ArrowCursor );
661 }
662 d->currTab.type = T_INVALID; // added (DF)
663}
664
665void KoRuler::mouseMoveEvent( TQMouseEvent *e )
666{
667 hasToDelete = false;
668
669 int pw = d->frameEnd - frameStart;
670 int ph = tqRound(zoomIt(d->layout.ptHeight));
671 int left = frameStart - diffx;
672 int top = tqRound(zoomIt(d->layout.ptTop));
673 top -= diffy;
674 int right = d->frameEnd - diffx;
675 int bottom = tqRound(zoomIt(d->layout.ptBottom));
676 bottom = ph - bottom - diffy;
677 // Cumulate first-line-indent
678 int ip_first = tqRound( zoomIt( i_first + ( d->rtl ? d->i_right : i_left) ) );
679 int ip_left = tqRound(zoomIt(i_left));
680 int ip_right = tqRound(zoomIt(d->i_right));
681
682 int mx = e->x();
683 mx = mx+diffx < 0 ? 0 : mx;
684 int my = e->y();
685 my = my+diffy < 0 ? 0 : my;
686
687 TQToolTip::remove( this);
688 switch ( orientation ) {
689 case TQt::Horizontal: {
690 if ( !d->mousePressed ) {
691 setCursor( ArrowCursor );
692 d->action = A_NONE;
694 // At the moment, moving the left and right border indicators
695 // is disabled when setFrameStartEnd has been called (i.e. in KWord)
696 // Changing the layout margins directly from it would be utterly wrong
697 // (just try the 2-columns modes...). What needs to be done is:
698 // emitting a signal frameResized in mouseReleaseEvent, when a left/right
699 // border has been moved, and in kword we need to update the margins from
700 // there, if the left border of the 1st column or the right border of the
701 // last column was moved... and find what to do with the other borders.
702 // And for normal frames, resize the frame without touching the page layout.
703 // All that is too much for now -> disabling.
704 if ( !m_bFrameStartSet )
705 {
706 if ( mx > left - 5 && mx < left + 5 ) {
707 setCursor( TQt::sizeHorCursor );
708 d->action = A_BR_LEFT;
709 } else if ( mx > right - 5 && mx < right + 5 ) {
710 setCursor( TQt::sizeHorCursor );
711 d->action = A_BR_RIGHT;
712 }
713 }
714 if ( d->flags & F_INDENTS ) {
715 int firstX = d->rtl ? right - ip_first : left + ip_first;
716 if ( mx > firstX - 5 && mx < firstX + 5 &&
717 my >= 2 && my <= d->pmFirst.size().height() + 2 ) {
718 TQToolTip::add( this, i18n("First line indent") );
719 setCursor( ArrowCursor );
720 d->action = A_FIRST_INDENT;
721 } else if ( mx > left + ip_left - 5 && mx < left + ip_left + 5 &&
722 my >= height() - d->pmLeft.size().height() - 2 && my <= height() - 2 ) {
723 TQToolTip::add( this, i18n("Left indent") );
724 setCursor( ArrowCursor );
725 d->action = A_LEFT_INDENT;
726 } else if ( mx > right - ip_right - 5 && mx < right - ip_right + 5 &&
727 my >= height() - d->pmLeft.size().height() - 2 && my <= height() - 2 ) {
728 TQToolTip::add( this, i18n("Right indent") );
729 setCursor( ArrowCursor );
730 d->action = A_RIGHT_INDENT;
731 }
732 }
733 if ( d->flags & F_TABS )
734 searchTab(mx);
735 } else {
736 // Calculate the new value.
737 int newPos=mx;
738 if( newPos!=right && gridSize!=0.0 && (e->state() & ShiftButton)==0) { // apply grid.
739 double grid=zoomIt(gridSize * 16);
740 newPos=tqRound( ((newPos * 16 / grid) * grid) / 16 );
741 }
742 if(newPos-left < 0) newPos=left;
743 else if (right-newPos < 0) newPos=right;
744 double newValue = unZoomIt(static_cast<double>(newPos) - frameStart + diffx);
745
746 switch ( d->action ) {
747 case A_BR_LEFT: {
748 if ( d->canvas && mx < right-10 && mx+diffx-2 > 0) {
749 drawLine( d->oldMx, mx );
750 d->layout.ptLeft = unZoomIt(static_cast<double>(mx + diffx));
751 if( ip_left > right-left-15 ) {
752 ip_left=right-left-15;
753 ip_left=ip_left<0 ? 0 : ip_left;
754 i_left=unZoomIt( ip_left );
755 emit newLeftIndent( i_left );
756 }
757 if ( ip_right > right-left-15 ) {
758 ip_right=right-left-15;
759 ip_right=ip_right<0? 0 : ip_right;
760 d->i_right=unZoomIt( ip_right );
761 emit newRightIndent( d->i_right );
762 }
763 d->oldMx = mx;
764 d->oldMy = my;
765 update();
766 }
767 else
768 return;
769 } break;
770 case A_BR_RIGHT: {
771 if ( d->canvas && mx > left+10 && mx+diffx <= pw-2) {
772 drawLine( d->oldMx, mx );
773 d->layout.ptRight = unZoomIt(static_cast<double>(pw - ( mx + diffx )));
774 if( ip_left > right-left-15 ) {
775 ip_left=right-left-15;
776 ip_left=ip_left<0 ? 0 : ip_left;
777 i_left=unZoomIt( ip_left );
778 emit newLeftIndent( i_left );
779 }
780 if ( ip_right > right-left-15 ) {
781 ip_right=right-left-15;
782 ip_right=ip_right<0? 0 : ip_right;
783 d->i_right=unZoomIt( ip_right );
784 emit newRightIndent( d->i_right );
785 }
786 d->oldMx = mx;
787 d->oldMy = my;
788 update();
789 }
790 else
791 return;
792 } break;
793 case A_FIRST_INDENT: {
794 if ( d->canvas ) {
795 if (d->rtl)
796 newValue = unZoomIt(pw) - newValue - d->i_right;
797 else
798 newValue -= i_left;
799 if(newValue == i_first) break;
800 drawLine( d->oldMx, newPos);
801 d->oldMx=newPos;
802 i_first = newValue;
803 update();
804 }
805 } break;
806 case A_LEFT_INDENT: {
807 if ( d->canvas ) {
808 //if (d->rtl) newValue = unZoomIt(pw) - newValue;
809 if(newValue == i_left) break;
810
811 drawLine( d->oldMx, newPos);
812 i_left = newValue;
813 d->oldMx = newPos;
814 update();
815 }
816 } break;
817 case A_RIGHT_INDENT: {
818 if ( d->canvas ) {
819 double rightValue = unZoomIt(right - newPos);
820 //if (d->rtl) rightValue = unZoomIt(pw) - rightValue;
821 if(rightValue == d->i_right) break;
822
823 drawLine( d->oldMx, newPos);
824 d->i_right=rightValue;
825 d->oldMx = newPos;
826 update();
827 }
828 } break;
829 case A_TAB: {
830 if ( d->canvas) {
831 if (d->rtl) newValue = unZoomIt(pw) - newValue;
832 if(newValue == d->currTab.ptPos) break; // no change
833 TQPainter p( d->canvas );
834 p.setRasterOp( TQt::NotROP );
835 // prevent 1st drawLine when we just created a new tab
836 // (it's a NOT line)
837 double pt;
838 int pt_fr;
839 if( d->currTab != d->removeTab )
840 {
841 pt = applyRtlAndZoom(d->currTab.ptPos);
842 pt_fr = tqRound(pt) + frameStart - diffx;
843 p.drawLine( pt_fr, 0, pt_fr, d->canvas->height() );
844 }
845
846 KoTabulatorList::Iterator it = d->tabList.find( d->currTab );
847 Q_ASSERT( it != d->tabList.end() );
848 if ( it != d->tabList.end() )
849 (*it).ptPos = newValue;
850 d->currTab.ptPos = newValue;
851
852 pt = applyRtlAndZoom( newValue );
853 pt_fr = tqRound(pt) + frameStart - diffx;
854 p.drawLine( pt_fr, 0, pt_fr, d->canvas->height() );
855
856 p.end();
857 d->oldMx = mx;
858 d->oldMy = my;
859 d->removeTab.type = T_INVALID;
860 update();
861 }
862 } break;
863 default: break;
864 }
865 }
866 if( d->action == A_HELPLINES )
867 {
868 emit moveGuide( e->pos(), true, size().height() );
869 emit moveHelpLines( e->pos(), true );
870 }
871
872 return;
873 } break;
874 case TQt::Vertical: {
875 if ( !d->mousePressed ) {
876 setCursor( ArrowCursor );
877 d->action = A_NONE;
878 if ( d->flags & F_NORESIZE )
879 break;
880 if ( my > top - 5 && my < top + 5 ) {
881 TQToolTip::add( this, i18n("Top margin") );
882 setCursor( TQt::sizeVerCursor );
883 d->action = A_BR_TOP;
884 } else if ( my > bottom - 5 && my < bottom + 5 ) {
885 TQToolTip::add( this, i18n("Bottom margin") );
886 setCursor( TQt::sizeVerCursor );
887 d->action = A_BR_BOTTOM;
888 }
889 } else {
890 switch ( d->action ) {
891 case A_BR_TOP: {
892 if ( d->canvas && my < bottom-20 && my+diffy-2 > 0) {
893 TQPainter p( d->canvas );
894 p.setRasterOp( TQt::NotROP );
895 p.drawLine( 0, d->oldMy, d->canvas->width(), d->oldMy );
896 p.drawLine( 0, my, d->canvas->width(), my );
897 p.end();
898 d->layout.ptTop = unZoomIt(static_cast<double>(my + diffy));
899 d->oldMx = mx;
900 d->oldMy = my;
901 update();
902 }
903 else
904 return;
905 } break;
906 case A_BR_BOTTOM: {
907 if ( d->canvas && my > top+20 && my+diffy < ph-2) {
908 TQPainter p( d->canvas );
909 p.setRasterOp( TQt::NotROP );
910 p.drawLine( 0, d->oldMy, d->canvas->width(), d->oldMy );
911 p.drawLine( 0, my, d->canvas->width(), my );
912 p.end();
913 d->layout.ptBottom = unZoomIt(static_cast<double>(ph - ( my + diffy )));
914 d->oldMx = mx;
915 d->oldMy = my;
916 update();
917 }
918 else
919 return;
920 } break;
921 default: break;
922 }
923 }
924
925 if( d->action == A_HELPLINES )
926 {
927 emit moveGuide( e->pos(), false, size().width() );
928 emit moveHelpLines( e->pos(), false );
929 }
930 } break;
931 }
932
933 d->oldMx = mx;
934 d->oldMy = my;
935}
936
937void KoRuler::resizeEvent( TQResizeEvent *e )
938{
939 TQFrame::resizeEvent( e );
940 buffer.resize( size() );
941}
942
943void KoRuler::mouseDoubleClickEvent( TQMouseEvent* )
944{
945 handleDoubleClick();
946}
947
948void KoRuler::handleDoubleClick()
949{
950 if ( !d->m_bReadWrite )
951 return;
952
953 d->doubleClickedIndent = false;
954 if ( d->tabChooser && ( d->flags & F_TABS ) ) {
955 // Double-click and mousePressed inserted a tab -> need to remove it
956 if ( d->tabChooser->getCurrTabType() != 0 && d->removeTab.type != T_INVALID && !d->tabList.isEmpty()) {
957 uint c = d->tabList.count();
958 d->tabList.remove( d->removeTab );
959 Q_ASSERT( d->tabList.count() < c );
960
961 d->removeTab.type = T_INVALID;
962 d->currTab.type = T_INVALID;
963 emit tabListChanged( d->tabList );
964 setCursor( ArrowCursor );
965 update();
966 // --- we didn't click on a tab, fall out to indents test ---
967 } else if ( d->action == A_TAB ) {
968 // Double-click on a tab
969 emit doubleClicked( d->currTab.ptPos ); // usually paragraph dialog
970 return;
971 }
972 }
973
974 // When Binary Compatibility is broken this will hopefully emit a
975 // doubleClicked(int) to differentiate between double-clicking an
976 // indent and double-clicking the ruler
977 if ( d->flags & F_INDENTS ) {
978 if ( d->action == A_LEFT_INDENT || d->action == A_RIGHT_INDENT || d->action == A_FIRST_INDENT ) {
979 d->doubleClickedIndent = true;
980 emit doubleClicked(); // usually paragraph dialog
981 return;
982 }
983 }
984
985 // Double-clicked nothing
986 d->action = A_NONE;
987 emit doubleClicked(); // usually page layout dialog
988}
989
990void KoRuler::setTabList( const KoTabulatorList & _tabList )
991{
992 d->tabList = _tabList;
993 qHeapSort(d->tabList); // "Trust no one." as opposed to "In David we trust."
994
995 // Note that d->currTab and d->removeTab could now point to
996 // tabs which don't exist in d->tabList
997
998 update();
999}
1000
1001double KoRuler::makeIntern( double _v )
1002{
1003 return KoUnit::fromUserValue( _v, m_unit );
1004}
1005
1006void KoRuler::setupMenu()
1007{
1008 d->rb_menu = new TQPopupMenu();
1009 TQ_CHECK_PTR( d->rb_menu );
1010 for ( uint i = 0 ; i <= KoUnit::U_LASTUNIT ; ++i )
1011 {
1012 KoUnit::Unit unit = static_cast<KoUnit::Unit>( i );
1013 d->rb_menu->insertItem( KoUnit::unitDescription( unit ), i /*as id*/ );
1014 if ( m_unit == unit )
1015 d->rb_menu->setItemChecked( i, true );
1016 }
1017 connect( d->rb_menu, TQ_SIGNAL( activated( int ) ), TQ_SLOT( slotMenuActivated( int ) ) );
1018
1019 d->rb_menu->insertSeparator();
1020 d->mPageLayout=d->rb_menu->insertItem(i18n("Page Layout..."), this, TQ_SLOT(pageLayoutDia()));
1021 d->rb_menu->insertSeparator();
1022 d->mRemoveTab=d->rb_menu->insertItem(i18n("Remove Tabulator"), this, TQ_SLOT(rbRemoveTab()));
1023 d->rb_menu->setItemEnabled( d->mRemoveTab, false );
1024}
1025
1026void KoRuler::uncheckMenu()
1027{
1028 for ( uint i = 0 ; i <= KoUnit::U_LASTUNIT ; ++i )
1029 d->rb_menu->setItemChecked( i, false );
1030}
1031
1032void KoRuler::setUnit( const TQString& _unit )
1033{
1034 setUnit( KoUnit::unit( _unit ) );
1035}
1036
1038{
1039 m_unit = unit;
1040 uncheckMenu();
1041 d->rb_menu->setItemChecked( m_unit, true );
1042 update();
1043}
1044
1045void KoRuler::setZoom( const double& zoom )
1046{
1047 if(zoom==m_zoom)
1048 return;
1049 if(zoom < 1E-4) // Don't do 0 or negative values
1050 return;
1051 m_zoom=zoom;
1052 m_1_zoom=1/m_zoom;
1053 update();
1054}
1055
1056bool KoRuler::willRemoveTab( int y ) const
1057{
1058 return (y < -50 || y > height() + 25) && d->currTab.type != T_INVALID;
1059}
1060
1061void KoRuler::rbRemoveTab() {
1062
1063 d->tabList.remove( d->currTab );
1064 d->currTab.type = T_INVALID;
1065 emit tabListChanged( d->tabList );
1066 update();
1067}
1068
1069void KoRuler::setReadWrite(bool _readWrite)
1070{
1071 d->m_bReadWrite=_readWrite;
1072}
1073
1074void KoRuler::searchTab(int mx) {
1075
1076 int pos;
1077 d->currTab.type = T_INVALID;
1078 KoTabulatorList::ConstIterator it = d->tabList.begin();
1079 for ( ; it != d->tabList.end() ; ++it ) {
1080 pos = tqRound(applyRtlAndZoom((*it).ptPos)) - diffx + frameStart;
1081 if ( mx > pos - 5 && mx < pos + 5 ) {
1082 setCursor( TQt::sizeHorCursor );
1083 d->action = A_TAB;
1084 d->currTab = *it;
1085 break;
1086 }
1087 }
1088}
1089
1090void KoRuler::drawLine(int oldX, int newX) {
1091
1092 TQPainter p( d->canvas );
1093 p.setRasterOp( TQt::NotROP );
1094 p.drawLine( oldX, 0, oldX, d->canvas->height() );
1095 if(newX!=-1)
1096 p.drawLine( newX, 0, newX, d->canvas->height() );
1097 p.end();
1098}
1099
1100void KoRuler::showMousePos( bool _showMPos )
1101{
1102 showMPos = _showMPos;
1103 hasToDelete = false;
1104 mposX = -1;
1105 mposY = -1;
1106 update();
1107}
1108
1109void KoRuler::setOffset( int _diffx, int _diffy )
1110{
1111 //kdDebug() << "KoRuler::setOffset " << _diffx << "," << _diffy << endl;
1112 diffx = _diffx;
1113 diffy = _diffy;
1114 update();
1115}
1116
1117void KoRuler::setFrameStartEnd( int _frameStart, int _frameEnd )
1118{
1119 if ( _frameStart != frameStart || _frameEnd != d->frameEnd || !m_bFrameStartSet )
1120 {
1121 frameStart = _frameStart;
1122 d->frameEnd = _frameEnd;
1123 // Remember that setFrameStartEnd was called. This activates a slightly
1124 // different mode (when moving start and end positions).
1125 m_bFrameStartSet = true;
1126 update();
1127 }
1128}
1129
1130void KoRuler::setRightIndent( double _right )
1131{
1132 d->i_right = makeIntern( _right );
1133 update();
1134}
1135
1137{
1138 d->rtl = rtl;
1139 update();
1140}
1141
1142void KoRuler::changeFlags(int _flags)
1143{
1144 d->flags = _flags;
1145}
1146
1148{
1149 return d->flags;
1150}
1151
1153{
1154 return d->doubleClickedIndent;
1155}
1156
1157double KoRuler::applyRtlAndZoom( double value ) const
1158{
1159 int frameWidth = d->frameEnd - frameStart;
1160 return d->rtl ? ( frameWidth - zoomIt( value ) ) : zoomIt( value );
1161}
1162
1163double KoRuler::unZoomItRtl( int pixValue ) const
1164{
1165 int frameWidth = d->frameEnd - frameStart;
1166 return d->rtl ? ( unZoomIt( (double)(frameWidth - pixValue) ) ) : unZoomIt( (double)pixValue );
1167}
1168
1169void KoRuler::slotMenuActivated( int i )
1170{
1171 if ( i >= 0 && i <= KoUnit::U_LASTUNIT )
1172 {
1173 KoUnit::Unit unit = static_cast<KoUnit::Unit>(i);
1174 setUnit( unit );
1175 emit unitChanged( unit );
1176 }
1177}
1178
1180{
1181 TQSize size;
1182 TQFont font = TDEGlobalSettings::toolBarFont();
1183 TQFontMetrics fm( font );
1184
1185 size.setWidth( TQMAX( fm.height() + 4, 20 ) );
1186 size.setHeight( TQMAX( fm.height() + 4, 20 ) );
1187
1188 return size;
1189}
1190
1191TQSize KoRuler::sizeHint() const
1192{
1193 return minimumSizeHint();
1194}
1195
1197{
1198 d->layout = _layout;
1199 update();
1200}
1201
1202#include "KoRuler.moc"
void changeFlags(int _flags)
Change the flag (i.e.
Definition KoRuler.cpp:1142
virtual TQSize sizeHint() const
Reimplemented from TQWidget.
Definition KoRuler.cpp:1191
void doubleClicked()
This signal is emitted when double-clicking the ruler (or an indent)
virtual TQSize minimumSizeHint() const
Reimplemented from TQWidget.
Definition KoRuler.cpp:1179
bool doubleClickedIndent() const
Definition KoRuler.cpp:1152
void setReadWrite(bool _readWrite)
KoRuler is in "read write" mode by default.
Definition KoRuler.cpp:1069
void setPageLayout(const KoPageLayout &_layout)
Set the page layout, see KoPageLayout.
Definition KoRuler.cpp:1196
void setTabList(const KoTabulatorList &tabList)
Set the list of tabulators to show in the ruler.
Definition KoRuler.cpp:990
void setMousePos(int mx, int my)
Set the position of the mouse, to update the indication in the ruler.
Definition KoRuler.cpp:155
void setRightIndent(double _right)
Set the [paragraph] right indent to the specified position (in the current unit)
Definition KoRuler.cpp:1130
void setUnit(const TQString &unit) TDE_DEPRECATED
Set the unit to be used.
Definition KoRuler.cpp:1032
void setDirection(bool rtl)
Set the [paragraph] direction.
Definition KoRuler.cpp:1136
KoRuler(TQWidget *_parent, TQWidget *_canvas, TQt::Orientation _orientation, const KoPageLayout &_layout, int _flags, KoUnit::Unit _unit, KoTabChooser *_tabChooser=0L)
Create a ruler TODO document params.
Definition KoRuler.cpp:82
void setZoom(const double &zoom=1.0)
Set the zoom of the ruler (default value of 1.0 is 100%)
Definition KoRuler.cpp:1045
int flags() const
Definition KoRuler.cpp:1147
void openPageLayoutDia()
Old signal, kept for compatibility.
const double & zoom() const
Definition KoRuler.h:139
void showMousePos(bool _showMPos)
Call showMousePos(true) if the ruler should indicate the position of the mouse.
Definition KoRuler.cpp:1100
void setPageLayoutMenuItemEnabled(bool b)
Enable or disable the "Page Layout" menu item.
Definition KoRuler.cpp:149
void setFrameStartEnd(int _frameStart, int _frameEnd)
Set the start and the end of the current 'frame', i.e.
Definition KoRuler.cpp:1117
void setOffset(int _diffx, int _diffy)
Set a global offset to the X and Y coordinates.
Definition KoRuler.cpp:1109
static double toUserValue(double ptValue, Unit unit)
This method is the one to use to display a value in a dialog.
Definition KoUnit.cpp:68
static double fromUserValue(double value, Unit unit)
This method is the one to use to read a value from a dialog.
Definition KoUnit.cpp:120
static TQString unitDescription(Unit _unit)
Get the full (translated) description of a unit.
Definition KoUnit.cpp:43
Unit
Length units supported by KOffice.
Definition KoUnit.h:63
static Unit unit(const TQString &_unitName, bool *ok=0)
Convert a unit name into a Unit enum.
Definition KoUnit.cpp:182
TDEAction * action(StdAction act_enum, const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0L)
This structure defines the page layout, including its size in pt, its format (e.g.
Struct: KoTabulator Defines the position of a tabulation (in pt), and its type.
Definition KoRuler.h:46
KoTabulators type
Type of tab (left/center/right/decimalpoint)
Definition KoRuler.h:54
KoTabulatorFilling filling
Type of tab filling.
Definition KoRuler.h:58
double ptPos
Position of the tab in pt.
Definition KoRuler.h:50
TQChar alignChar
Alignment character.
Definition KoRuler.h:66
double ptWidth
Width of the tab filling line.
Definition KoRuler.h:62