karbon

vselecttool.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001, 2002, 2003 The Karbon Developers
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#include <math.h>
21#include <stdlib.h>
22
23#include <tqcursor.h>
24#include <tqlabel.h>
25#include <tqradiobutton.h>
26#include <tqbuttongroup.h>
27
28#include <KoPoint.h>
29#include <KoRect.h>
30#include <kdebug.h>
31
32#include <karbon_part.h>
33#include <karbon_view.h>
34#include <render/vpainter.h>
35#include <render/vpainterfactory.h>
36#include <core/vselection.h>
37#include "vselecttool.h"
38#include <commands/vtransformcmd.h>
39#include <visitors/vselectiondesc.h>
40#include <visitors/vselectobjects.h>
41#include <widgets/vcanvas.h>
42
43VSelectOptionsWidget::VSelectOptionsWidget( KarbonPart *part )
44 : KDialogBase( 0L, "", true, i18n( "Selection" ), Ok | Cancel ), m_part( part )
45{
46 TQButtonGroup *group = new TQButtonGroup( 1, TQt::Horizontal, i18n( "Selection Mode" ), this );
47
48 new TQRadioButton( i18n( "Select in current layer" ), group );
49 new TQRadioButton( i18n( "Select in visible layers" ), group );
50 new TQRadioButton( i18n( "Select in selected layers" ), group );
51
52 group->setRadioButtonExclusive( true );
53 group->setButton( part->document().selectionMode() );
54
55 connect( group, TQ_SIGNAL( clicked( int ) ), this, TQ_SLOT( modeChange( int ) ) );
56
57 group->setInsideMargin( 4 );
58 group->setInsideSpacing( 2 );
59
60 setMainWidget( group );
61 setFixedSize( baseSize() );
62} // VSelectOptionsWidget::VSelectOptionsWidget
63
64void VSelectOptionsWidget::modeChange( int mode )
65{
66 m_part->document().setSelectionMode( (VDocument::VSelectionMode)mode );
67} // VSelectOptionsWidget::modeChanged
68
69VSelectTool::VSelectTool( KarbonView *view )
70 : VTool( view, "tool_select" ), m_state( normal )
71{
72 m_lock = false;
73 m_add = true;
74 m_objects.setAutoDelete( true );
75 m_optionsWidget = new VSelectOptionsWidget( view->part() );
76 registerTool( this );
77 connect( view, TQ_SIGNAL( selectionChange() ), this, TQ_SLOT( updateStatusBar() ) );
78}
79
80VSelectTool::~VSelectTool()
81{
82 delete m_optionsWidget;
83}
84
85void
87{
89 view()->setCursor( TQCursor( TQt::arrowCursor ) );
90 view()->part()->document().selection()->showHandle();
91 view()->part()->document().selection()->setSelectObjects();
92 view()->part()->document().selection()->setState( VObject::selected );
93 view()->part()->document().selection()->selectNodes();
94 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
95 updateStatusBar();
96}
97
98TQString
100{
101 return i18n( "Select" );
102}
103
105{
106 TQString s = i18n( "<qt><b>Selection tool:</b><br>" );
107 s += i18n( "<i>Select in current layer:</i><br>The selection is made in the layer selected in the layers docker.<br><br>" );
108 s += i18n( "<i>Select in visible layers:</i><br>The selection is made in the visible layers (eye in the layers docker).<br><br>" );
109 s += i18n( "<i>Select in selected layers:</i><br>The selection is made in the checked layers in the layers docker.<br><br>" );
110 s += i18n( "<i>Position using arrow keys</i><br>The selection can be positioned up, down, left and right using the corresponding arrow keys." );
111 return s;
112} // VSelectTool::contextHelp
113
114void
115VSelectTool::draw()
116{
117 VPainter *painter = view()->painterFactory()->editpainter();
118 //painter->setZoomFactor( view()->zoom() );
119 painter->setRasterOp( TQt::NotROP );
120
121 KoRect rect = view()->part()->document().selection()->boundingBox();
122
123 if( m_state != normal )
124 {
125 VObjectListIterator itr = m_objects;
126 for( ; itr.current(); ++itr )
127 {
128 itr.current()->draw( painter, &itr.current()->boundingBox() );
129 }
130 }
131 else if( m_state == normal )
132 {
133 painter->setPen( TQt::DotLine );
134 painter->newPath();
135 painter->moveTo( KoPoint( first().x(), first().y() ) );
136 painter->lineTo( KoPoint( m_current.x(), first().y() ) );
137 painter->lineTo( KoPoint( m_current.x(), m_current.y() ) );
138 painter->lineTo( KoPoint( first().x(), m_current.y() ) );
139 painter->lineTo( KoPoint( first().x(), first().y() ) );
140 painter->strokePath();
141
142 m_state = normal;
143 }
144}
145
146void
148{
149 if( m_state != normal || !view() ) return;
150 switch( view()->part()->document().selection()->handleNode( last() ) )
151 {
152 case node_lt:
153 case node_rb:
154 view()->setCursor( TQCursor( TQt::SizeFDiagCursor ) );
155 break;
156 case node_rt:
157 case node_lb:
158 view()->setCursor( TQCursor( TQt::SizeBDiagCursor ) );
159 break;
160 case node_lm:
161 case node_rm:
162 view()->setCursor( TQCursor( TQt::SizeHorCursor ) );
163 break;
164 case node_mt:
165 case node_mb:
166 view()->setCursor( TQCursor( TQt::SizeVerCursor ) );
167 break;
168 default:
169 view()->setCursor( TQCursor( TQt::arrowCursor ) );
170 }
171}
172
173void
175{
176 // we are adding to the selection
177 m_add = true;
178
179 m_current = first();
180
181 m_activeNode = view()->part()->document().selection()->handleNode( first() );
182 KoRect rect = view()->part()->document().selection()->boundingBox();
183
184 if( m_activeNode != node_none )
185 m_state = scaling;
186 else if( rect.contains( m_current ) && m_state == normal )
187 m_state = moving;
188
189 recalc();
190
191 // undraw selection bounding box
192 view()->part()->document().selection()->setState( VObject::edit );
193 view()->repaintAll( rect );
194 view()->part()->document().selection()->setState( VObject::selected );
195
196 draw();
197}
198
199void
201{
202 // we are removing from the selection
203 m_add = false;
204
205 m_current = first();
206
207 recalc();
208
209 // undraw selection bounding box
210 view()->part()->document().selection()->setState( VObject::edit );
211 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
212 view()->part()->document().selection()->setState( VObject::selected );
213
214 draw();
215}
216
217void
219{
220 draw();
221
222 recalc();
223
224 draw();
225}
226
227void
229{
230 m_state = normal;
231 m_add = true;
232
233 if( ctrlPressed() )
234 {
235 // unselect the topmost object under the mouse cursor
236 VObjectList newSelection;
237 VSelectObjects selector( newSelection, first() );
238 if( selector.visit( view()->part()->document() ) )
239 view()->part()->document().selection()->take( *newSelection.last() );
240
241 view()->part()->repaintAllViews( view()->part()->document().selection()->boundingBox() );
242 view()->selectionChanged();
243
244 updateStatusBar();
245 }
246 else if( view()->part()->document().selection()->objects().count() > 0 )
247 {
248 view()->showSelectionPopupMenu( TQCursor::pos() );
249 }
250}
251
252void
254{
255 m_state = normal;
256 m_add = true;
257
258 // selection of next underlying object
259 if( shiftPressed() )
260 {
261 VObjectList newSelection;
262 VObjectList oldSelection = view()->part()->document().selection()->objects();
263
264 // clear selection if not in multi-slection-mode
265 if( ! ctrlPressed() )
266 view()->part()->document().selection()->clear();
267
268 // get a list of all object under the mouse cursor
269 VSelectObjects selector( newSelection, first(), true, true );
270 if( selector.visit( view()->part()->document() ) )
271 {
272 // determine the last selected object of the object stack
273 VObject *lastMatched = 0L;
274 VObjectListIterator it( newSelection );
275 for( ; it.current(); ++it )
276 {
277 if( oldSelection.contains( it.current() ) )
278 lastMatched = it.current();
279 }
280
281 // select the next underlying object or the first if:
282 // - none is selected
283 // - the stack's bottom object was the last selected object
284 if( lastMatched && lastMatched != newSelection.first() )
285 view()->part()->document().selection()->append( newSelection.at( newSelection.find( lastMatched )-1 ) );
286 else
287 view()->part()->document().selection()->append( newSelection.last() );
288 }
289 }
290 else
291 {
292 // clear selection if not in multi-slection-mode
293 if( ! ctrlPressed() )
294 view()->part()->document().selection()->clear();
295
296 // append the topmost object under the mouse cursor to the selection
297 VObjectList newSelection;
298 VSelectObjects selector( newSelection, first() );
299 if( selector.visit( view()->part()->document() ) )
300 view()->part()->document().selection()->append( newSelection.last() );
301 }
302
303 view()->part()->repaintAllViews( view()->part()->document().selection()->boundingBox() );
304 view()->selectionChanged();
305
306 updateStatusBar();
307}
308
309void
311{
312 if( m_state == normal )
313 {
314 // Y mirroring
315 KoPoint fp = first();
316 KoPoint lp = last();
317 if( ! ctrlPressed() )
318 view()->part()->document().selection()->clear();
319
320 KoRect selRect = KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize();
321 if( m_add )
322 view()->part()->document().selection()->append( selRect );
323 else
324 view()->part()->document().selection()->take( selRect );
325 view()->part()->repaintAllViews( selRect );
326 }
327 else if( m_state == moving )
328 {
329 m_state = normal;
330 recalc();
331 if( m_lock )
332 view()->part()->addCommand(
333 new VTranslateCmd(
334 &view()->part()->document(),
335 abs( int( m_distx ) ) >= abs( int( m_disty ) ) ? tqRound( m_distx ) : 0,
336 abs( int( m_distx ) ) <= abs( int( m_disty ) ) ? tqRound( m_disty ) : 0, altPressed() ),
337 true );
338 else
339 view()->part()->addCommand(
340 new VTranslateCmd( &view()->part()->document(), tqRound( m_distx ), tqRound( m_disty ), altPressed() ),
341 true );
342 }
343 else if( m_state == scaling )
344 {
345 m_state = normal;
346 view()->part()->addCommand(
347 new VScaleCmd( &view()->part()->document(), m_sp, m_s1, m_s2, altPressed() ),
348 true );
349 m_s1 = m_s2 = 1;
350 }
351
352 view()->selectionChanged();
353 m_lock = false;
354 updateStatusBar();
355}
356
357void
358VSelectTool::arrowKeyReleased( TQt::Key key )
359{
360 int dx = 0;
361 int dy = 0;
362 switch( key )
363 {
364 case TQt::Key_Up: dy = 10; break;
365 case TQt::Key_Down: dy = -10; break;
366 case TQt::Key_Right: dx = 10; break;
367 case TQt::Key_Left: dx = -10; break;
368 default: return;
369 }
370 m_state = normal;
371 view()->part()->addCommand(
372 new VTranslateCmd(
373 &view()->part()->document(),
374 dx, dy ),
375 true );
376 view()->selectionChanged();
377 updateStatusBar();
378}
379
380bool
381VSelectTool::keyReleased( TQt::Key key )
382{
383
384 VSelection* selection = view()->part()->document().selection();
385
386 switch( key )
387 {
388 // increase/decrease the handle size
389 case TQt::Key_I:
390 {
391 uint handleSize = selection->handleSize();
392 if( shiftPressed() )
393 selection->setHandleSize( ++handleSize );
394 else if( handleSize > 1 )
395 selection->setHandleSize( --handleSize );
396 }
397 break;
398 default: return false;
399 }
400
401 if( view() )
402 view()->repaintAll( selection->boundingBox() );
403
404 return true;
405}
406
407void
408VSelectTool::updateStatusBar() const
409{
410 if( ! view() )
411 return;
412
413 if( ! view()->part() )
414 return;
415
416 int objcount = view()->part()->document().selection()->objects().count();
417 if( objcount > 0 )
418 {
419 KoRect rect = view()->part()->document().selection()->boundingBox();
420
421 double x = KoUnit::toUserValue( rect.x(), view()->part()->unit() );
422 double y = KoUnit::toUserValue( rect.y(), view()->part()->unit() );
423 double r = KoUnit::toUserValue( rect.right(), view()->part()->unit() );
424 double b = KoUnit::toUserValue( rect.bottom(), view()->part()->unit() );
425
426 // print bottom-left (%1,%2), top-right (%3,%4) corner of selection bounding box and document unit (%5)
427 TQString selectMessage = i18n( "[(left,bottom), (right,top)] (actual unit)", "Selection [(%1, %2), (%3, %4)] (%5)").arg( x, 0, 'f', 1 ).arg( y, 0, 'f', 1 ).arg( r, 0, 'f', 1 ).arg( b, 0, 'f', 1 ).arg( view()->part()->unitName() );
428
429 VSelectionDescription selectionDesc;
430 selectionDesc.visit( *view()->part()->document().selection() );
431 selectMessage += TQString( "(%1)" ).arg( selectionDesc.description() );
432
433 view()->statusMessage()->setText( selectMessage );
434 }
435 else
436 view()->statusMessage()->setText( i18n( "No selection" ) );
437}
438
439void
441{
442 m_lock = true;
443}
444
445void
447{
448 m_lock = false;
449}
450
451void
453{
454 draw();
455
456 recalc();
457
458 draw();
459}
460
461void
463{
464 draw();
465
466 recalc();
467
468 draw();
469}
470
471void
473{
474 // Erase old object:
475 if ( isDragging() )
476 {
477 draw();
478 m_state = normal;
479 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
480 }
481}
482
483void
484VSelectTool::recalc()
485{
486 if( m_state == normal )
487 {
488 m_current = last();
489 }
490 else
491 {
492 VTransformCmd* cmd;
493 KoPoint _first = view()->canvasWidget()->snapToGrid( first() );
494 KoPoint _last = view()->canvasWidget()->snapToGrid( last() );
495 KoRect rect = view()->part()->document().selection()->boundingBox();
496
497 if( m_state == moving )
498 {
499 KoPoint p( rect.x() + last().x() - first().x(), rect.bottom() + last().y() - first().y() );
500 p = view()->canvasWidget()->snapToGrid( p );
501 m_distx = p.x() - rect.x();
502 m_disty = p.y() - rect.bottom();
503 if( m_lock )
504 cmd = new VTranslateCmd( 0L, abs( int( m_distx ) ) >= abs( int( m_disty ) ) ? m_distx : 0,
505 abs( int( m_distx ) ) <= abs( int( m_disty ) ) ? m_disty : 0 );
506 else
507 cmd = new VTranslateCmd( 0L, m_distx, m_disty );
508 }
509 else
510 {
511 if( m_activeNode == node_lb )
512 {
513 m_sp = KoPoint( rect.right(), rect.bottom() );
514 m_s1 = ( rect.right() - _last.x() ) / double( rect.width() );
515 m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() );
516 }
517 else if( m_activeNode == node_mb )
518 {
519 m_sp = KoPoint( ( ( rect.right() + rect.left() ) / 2 ), rect.bottom() );
520 m_s1 = 1;
521 m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() );
522 }
523 else if( m_activeNode == node_rb )
524 {
525 m_sp = KoPoint( rect.x(), rect.bottom() );
526 m_s1 = ( _last.x() - rect.x() ) / double( rect.width() );
527 m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() );
528 }
529 else if( m_activeNode == node_rm)
530 {
531 m_sp = KoPoint( rect.x(), ( rect.bottom() + rect.top() ) / 2 );
532 m_s1 = ( _last.x() - rect.x() ) / double( rect.width() );
533 m_s2 = 1;
534 }
535 else if( m_activeNode == node_rt )
536 {
537 m_sp = KoPoint( rect.x(), rect.y() );
538 m_s1 = ( _last.x() - rect.x() ) / double( rect.width() );
539 m_s2 = ( _last.y() - rect.y() ) / double( rect.height() );
540 }
541 else if( m_activeNode == node_mt )
542 {
543 m_sp = KoPoint( ( ( rect.right() + rect.left() ) / 2 ), rect.y() );
544 m_s1 = 1;
545 m_s2 = ( _last.y() - rect.y() ) / double( rect.height() );
546 }
547 else if( m_activeNode == node_lt )
548 {
549 m_sp = KoPoint( rect.right(), rect.y() );
550 m_s1 = ( rect.right() - _last.x() ) / double( rect.width() );
551 m_s2 = ( _last.y() - rect.y() ) / double( rect.height() );
552 }
553 else if( m_activeNode == node_lm )
554 {
555 m_sp = KoPoint( rect.right(), ( rect.bottom() + rect.top() ) / 2 );
556 m_s1 = ( rect.right() - _last.x() ) / double( rect.width() );
557 m_s2 = 1;
558 }
559
560 if( shiftPressed() )
561 m_s1 = m_s2 = kMax( m_s1, m_s2 );
562 cmd = new VScaleCmd( 0L, m_sp, m_s1, m_s2 );
563 }
564
565 // Copy selected objects and transform:
566 m_objects.clear();
567 VObject* copy;
568
569 VObjectListIterator itr = view()->part()->document().selection()->objects();
570 for( ; itr.current() ; ++itr )
571 {
572 if( itr.current()->state() != VObject::deleted )
573 {
574 copy = itr.current()->clone();
575 copy->setState( VObject::edit );
576
577 cmd->visit( *copy );
578
579 m_objects.append( copy );
580 }
581 }
582
583 delete( cmd );
584 }
585}
586
587bool
589{
590 return m_optionsWidget->exec() == TQDialog::Accepted;
591}
592
593void
595{
596 updateStatusBar();
597}
598
599void
600VSelectTool::setup( TDEActionCollection *collection )
601{
602 m_action = static_cast<TDERadioAction *>(collection -> action( name() ) );
603
604 if( m_action == 0 )
605 {
606 m_action = new TDERadioAction( i18n( "Select Tool" ), "14_select", TQt::SHIFT+TQt::Key_H, this, TQ_SLOT( activate() ), collection, name() );
607 m_action->setToolTip( i18n( "Select" ) );
608 m_action->setExclusiveGroup( "select" );
609 //m_ownAction = true;
610 }
611}
612
613#include "vselecttool.moc"
Keeps track of visual per document properties.
Definition karbon_part.h:46
void repaintAllViews(bool repaint=true)
repaint all views attached to this koDocument
void addCommand(VCommand *cmd, bool repaint=false)
insert a command into the undo/redo-history:
VSelection * selection() const
Returns a pointer to the selection.
Definition vdocument.h:238
VSelectionMode
The different selection modes.
Definition vdocument.h:56
VSelectionMode selectionMode()
Returns the selection mode.
Definition vdocument.h:246
virtual VObject * clone() const =0
Create an exact copy of this object.
virtual void setState(const VState state)
Sets the state to a specified new state.
Definition vobject.h:163
@ selected
visible, active and can be manipulated by tools
Definition vobject.h:61
@ deleted
deleted, nearly dead
Definition vobject.h:58
@ edit
visible, active and is currently manipulated by a tool
Definition vobject.h:62
const VObjectList & objects() const
Read only access to the selected objects.
Definition vselection.h:136
void append()
Adds all objects to the selection.
void clear()
Removes the references to all objects, not the objects themselves.
virtual void setSelectObjects(bool selectObjects=true)
Toggles selection of objects/nodes.
Definition vselection.h:173
void showHandle(bool handle=true)
Toggle selection handles on/off.
Definition vselection.h:166
void selectNodes(bool select=true)
Selects or deselects all nodes.
virtual const KoRect & boundingBox() const
Calculates the tightest bounding box around the object.
void take(VObject &object)
Removes the reference to the object, not the object itself.
VHandleNode handleNode(const KoPoint &point) const
Returns the handle node id, the KoPoint is inside.
The base class for all karbon tools.
Definition vtool.h:52
virtual void mouseDragRelease()
Mouse button release.
Definition vtool.h:220
virtual void mouseButtonPress()
Left mouse button press.
Definition vtool.h:185
const KoPoint & last() const
The last mouse coordinate.
Definition vtool.h:285
const KoPoint & first() const
Most tools need to know the first mouse coordinate.
Definition vtool.h:280
bool altPressed() const
The status of the alt key.
Definition vtool.h:306
virtual void rightMouseButtonRelease()
Right mouse button release.
Definition vtool.h:200
virtual void mouseButtonRelease()
Left mouse button release.
Definition vtool.h:195
bool ctrlPressed() const
The status of the ctrl key.
Definition vtool.h:299
virtual void mouseDragCtrlReleased()
"Ctrl" key released while mouse drag.
Definition vtool.h:240
TDERadioAction * action() const
Returns the tool's associated action object.
Definition vtool.h:151
virtual void cancel()
Cancels all tool operations.
Definition vtool.h:255
virtual TQString statusText()
The tool status text.
Definition vtool.h:108
virtual void activate()
Called during the tool activation.
Definition vtool.cpp:252
bool shiftPressed() const
The status of the shift key.
Definition vtool.h:292
virtual void mouseDragCtrlPressed()
Mouse drag with "Ctrl" key pressed at the same time.
Definition vtool.h:230
TDERadioAction * m_action
The tool's action object.
Definition vtool.h:309
virtual void mouseDragShiftPressed()
Mouse drag with "Shift" key pressed at the same time.
Definition vtool.h:225
bool isDragging() const
Returns the current dagging state.
Definition vtool.h:173
virtual void refreshUnit()
This function is called when the documents unit setting were changed.
Definition vtool.h:138
virtual void mouseDragShiftReleased()
"Shift" key released while mouse drag.
Definition vtool.h:235
virtual TQString contextHelp()
The context help of the tool.
Definition vtool.h:98
virtual void setCursor() const
This function is called on each mouse event the tool receives.
Definition vtool.h:180
virtual void rightMouseButtonPress()
Right mouse button press.
Definition vtool.h:190
virtual void mouseDrag()
Mouse drag.
Definition vtool.h:215
KarbonView * view() const
Returns the connected karbon part.
Definition vtool.cpp:66
virtual bool showDialog() const
Shows the tools option dialog.
Definition vtool.h:88
virtual bool visit(VObject &object)
General visit method.
Definition vvisitor.cpp:31