karbon

vselectnodestool.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002, 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
22#include <tqcursor.h>
23#include <tqlabel.h>
24
25#include <tdelocale.h>
26#include <KoPoint.h>
27#include <KoRect.h>
28
29#include <karbon_part.h>
30#include <karbon_view.h>
31
32#include <render/vpainter.h>
33#include <render/vpainterfactory.h>
34#include <visitors/vselectnodes.h>
35#include <commands/vtransformcmd.h>
36#include <visitors/vdrawselection.h>
37#include <core/vselection.h>
38#include <core/vcursor.h>
39#include "vselectnodestool.h"
40#include <vtransformnodes.h>
41#include <commands/vdeletenodescmd.h>
42#include <widgets/vcanvas.h>
43
44#include <kdebug.h>
45
46VSelectNodesTool::VSelectNodesTool( KarbonView* view )
47 : VTool( view, "tool_select_nodes" ), m_state( normal ), m_select( true )
48{
49 registerTool( this );
50}
51
52VSelectNodesTool::~VSelectNodesTool()
53{
54}
55
56void
58{
59 if( view() )
60 {
61 view()->setCursor( VCursor::needleArrow() );
62 view()->part()->document().selection()->showHandle( false );
63 view()->part()->document().selection()->setSelectObjects( false );
64 // deselect all nodes
65 view()->part()->document().selection()->selectNodes( false );
66 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
67 }
69}
70
71TQString
73{
74 if( m_state == normal )
75 return i18n( "Editing Nodes" );
76 else
77 return TQString( "" );
78}
79
80void
81VSelectNodesTool::draw()
82{
83 VPainter *painter = view()->painterFactory()->editpainter();
84 painter->setZoomFactor( view()->zoom() );
85 painter->setRasterOp( TQt::NotROP );
86
87 if( m_state == dragging )
88 {
89 painter->setPen( TQt::DotLine );
90 painter->newPath();
91 painter->moveTo( KoPoint( m_first.x(), m_first.y() ) );
92 painter->lineTo( KoPoint( m_current.x(), m_first.y() ) );
93 painter->lineTo( KoPoint( m_current.x(), m_current.y() ) );
94 painter->lineTo( KoPoint( m_first.x(), m_current.y() ) );
95 painter->lineTo( KoPoint( m_first.x(), m_first.y() ) );
96 painter->strokePath();
97 }
98 else
99 {
100 VDrawSelection op( m_objects, painter, true, VSelection::handleSize() );
101 VObjectListIterator itr = m_objects;
102 for( ; itr.current(); ++itr )
103 op.visit( *( itr.current() ) );
104 }
105}
106
107void
109{
110 if( m_state >= moving )
111 {
112 view()->setCursor( VCursor::needleMoveArrow() );
113 return;
114 }
115
116 KoRect selrect = calcSelRect( last() );
117
118 TQPtrList<VSegment> segments = view()->part()->document().selection()->getSegments( selrect );
119 if( segments.count() > 0 )
120 {
121 VSegment* seg = segments.at( 0 );
122 for( int i = 0; i < seg->degree(); ++i )
123 if( seg->pointIsSelected( i ) && selrect.contains( seg->point( i ) ) )
124 {
125 view()->setCursor( VCursor::needleMoveArrow() );
126 break;
127 }
128 }
129 else
130 view()->setCursor( VCursor::needleArrow() );
131}
132
133void
135{
136 m_first = m_current = first();
137
138 m_state = normal;
139 m_select = true;
140
141 recalc();
142
143 view()->part()->document().selection()->setState( VObject::edit );
144 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
145 view()->part()->document().selection()->setState( VObject::selected );
146
147 VSelection* selection = view()->part()->document().selection();
148
149 KoRect selrect = calcSelRect( m_current );
150
151 // get segments with control points inside selection rect
152 TQPtrList<VSegment> segments = selection->getSegments( selrect );
153 if( segments.count() > 0 )
154 {
155 VSegment *seg = segments.at( 0 );
156 VSegment* prev = seg->prev();
157 VSegment* next = seg->next();
158
159 // allow moving bezier points only if one of the bezier points is within the selection rect
160 // and no neighboring knot is selected
161 if( segments.count() == 1 && ! selrect.contains( seg->knot() ) && ! seg->knotIsSelected()
162 && ( prev && ! prev->knotIsSelected() ) )
163 {
164 if( selrect.contains( seg->point( 1 ) ) )
165 {
166 m_state = movingbezier1;
167 if( next )
168 next->selectPoint( 0, false );
169 }
170 else if( selrect.contains( seg->point( 0 ) ) )
171 {
172 m_state = movingbezier2;
173 if( prev )
174 prev->selectPoint( 1, false );
175 }
176 }
177 else
178 {
179 for( VSegment *seg = segments.first(); seg; seg = segments.next() )
180 {
181 for( int i = 0; i < seg->degree(); ++i )
182 {
183 if( seg->pointIsSelected( i ) && selrect.contains( seg->point( i ) ) )
184 {
185 m_state = moving;
186 break;
187 }
188 }
189 if( m_state == moving )
190 break;
191 }
192 }
193
194 double minDist = -1.0;
195 // use the nearest control point of all the segments as starting point
196 for( VSegment *seg = segments.first(); seg; seg = segments.next() )
197 {
198 for( int i = 0; i < seg->degree(); ++i )
199 {
200 if( selrect.contains( seg->point( i ) ) )
201 {
202 KoPoint vDist = seg->point( i ) - m_current;
203 double dist = vDist.x()*vDist.x() + vDist.y()*vDist.y();
204 if( minDist < 0.0 || dist < minDist )
205 {
206 m_first = seg->point( i );
207 minDist = dist;
208 }
209 }
210 }
211 }
212 recalc();
213 }
214 else
215 m_state = dragging;
216
217 draw();
218}
219
220void
222{
223 m_first = m_current = first();
224
225 m_state = normal;
226 m_select = false;
227
228 recalc();
229
230 view()->part()->document().selection()->setState( VObject::edit );
231 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
232 view()->part()->document().selection()->setState( VObject::selected );
233
234 draw();
235}
236
237bool
238VSelectNodesTool::keyReleased( TQt::Key key )
239{
240 VSelection* selection = view()->part()->document().selection();
241
242 switch( key )
243 {
244 // increase/decrease the handle size
245 case TQt::Key_I:
246 {
247 uint handleSize = selection->handleSize();
248 if( shiftPressed() )
249 selection->setHandleSize( ++handleSize );
250 else if( handleSize > 1 )
251 selection->setHandleSize( --handleSize );
252 }
253 break;
254 case TQt::Key_Delete:
255 if( selection->objects().count() > 0 )
256 view()->part()->addCommand( new VDeleteNodeCmd( &view()->part()->document() ), true );
257 break;
258 default: return false;
259 }
260
261 if( view() )
262 view()->repaintAll( selection->boundingBox() );
263
264 return true;
265}
266
267void
269{
270 // erase old object:
271 draw();
272
273 VSelection* selection = view()->part()->document().selection();
274
275 KoRect selrect = calcSelRect( last() );
276
277 if( ctrlPressed() )
278 selection->append( selrect.normalize(), false, false );
279 else
280 selection->append( selrect.normalize(), false, true );
281
282 view()->selectionChanged();
283 view()->part()->repaintAllViews();
284 m_state = normal;
285}
286
287void
289{
290 // erase old object:
291 draw();
292
293 VSelection* selection = view()->part()->document().selection();
294
295 KoRect selrect = calcSelRect( last() );
296
297 selection->take( selrect.normalize(), false, false );
298
299 view()->selectionChanged();
300 view()->part()->repaintAllViews();
301 m_state = normal;
302}
303
304void
306{
307 draw();
308
309 recalc();
310
311 draw();
312}
313
314void
316{
317 if( m_state >= moving )
318 {
319 view()->part()->document().selection()->setState( VObject::selected );
320 VCommand *cmd;
321 TQPtrList<VSegment> segments;
322 KoPoint _last = view()->canvasWidget()->snapToGrid( last() );
323 if( m_state == movingbezier1 || m_state == movingbezier2 )
324 {
325 KoRect selrect = calcSelRect( m_first );
326 segments = view()->part()->document().selection()->getSegments( selrect );
327 cmd = new VTranslateBezierCmd( &view()->part()->document(), segments.at( 0 ),
328 tqRound( ( _last.x() - m_first.x() ) ),
329 tqRound( ( _last.y() - m_first.y() ) ),
330 m_state == movingbezier2 );
331 }
332 else
333 {
334 cmd = new VTranslatePointCmd(
335 &view()->part()->document(),
336 tqRound( ( _last.x() - m_first.x() ) ),
337 tqRound( ( _last.y() - m_first.y() ) ) );
338 }
339 view()->part()->addCommand( cmd, true );
340 m_state = normal;
341 }
342 else
343 {
344 KoPoint fp = m_first;
345 KoPoint lp = last();
346
347 if ( (fabs(lp.x() - fp.x()) + fabs(lp.y()-fp.y())) < 3.0 )
348 {
349 // AK - should take the middle point here
350 fp = last() - KoPoint(8.0, 8.0);
351 lp = last() + KoPoint(8.0, 8.0);
352 }
353
354 // erase old object:
355 draw();
356
357 if( m_select )
358 {
359 view()->part()->document().selection()->append(); // select all
360 view()->part()->document().selection()->append(
361 KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize(),
362 false, true );
363 }
364 else
365 {
366 view()->part()->document().selection()->take(
367 KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize(),
368 false, false );
369 }
370 view()->selectionChanged();
371 view()->part()->repaintAllViews();
372 m_state = normal;
373 }
374}
375
376void
378{
379 // Erase old object:
380 if ( isDragging() )
381 {
382 draw();
383 m_state = normal;
384 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
385 }
386}
387
388void
389VSelectNodesTool::recalc()
390{
391 if( m_state == dragging )
392 {
393 m_current = last();
394 }
395 else if( m_state == moving || m_state == movingbezier1 || m_state == movingbezier2 )
396 {
397 KoPoint _last = view()->canvasWidget()->snapToGrid( last() );
398 double distx = _last.x() - m_first.x();
399 double disty = _last.y() - m_first.y();
400 // move operation
401 TQWMatrix mat;
402 mat.translate( distx, disty );
403
404 // Copy selected objects and transform:
405 m_objects.clear();
406 VObject* copy;
407
408 VTransformNodes op( mat );
409
410 VObjectListIterator itr = view()->part()->document().selection()->objects();
411 for ( ; itr.current() ; ++itr )
412 {
413 if( itr.current()->state() != VObject::deleted )
414 {
415 copy = itr.current()->clone();
416 copy->setState( VObject::edit );
417 op.visit( *copy );
418 m_objects.append( copy );
419 }
420 }
421 }
422}
423
424void
425VSelectNodesTool::setup( TDEActionCollection *collection )
426{
427 m_action = static_cast<TDERadioAction *>(collection -> action( name() ) );
428
429 if( m_action == 0 )
430 {
431 m_action = new TDERadioAction( i18n( "Select Nodes Tool" ), "14_selectnodes", TQt::SHIFT+TQt::Key_H, this, TQ_SLOT( activate() ), collection, name() );
432 m_action->setToolTip( i18n( "Select Nodes" ) );
433 m_action->setExclusiveGroup( "select" );
434 //m_ownAction = true;
435 }
436}
437
438KoRect
439VSelectNodesTool::calcSelRect( const KoPoint &pos ) const
440{
441 double tolerance = view()->part()->document().selection()->handleSize() / view()->zoom();
442 return KoRect( pos.x() - tolerance, pos.y() - tolerance, 2 * tolerance + 1.0, 2 * tolerance + 1.0 );
443}
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:
static TQCursor needleMoveArrow()
needle arrow with four way arrow
Definition vcursor.cpp:132
static TQCursor needleArrow()
needle arraow cursor
Definition vcursor.cpp:119
VSelection * selection() const
Returns a pointer to the selection.
Definition vdocument.h:238
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
bool pointIsSelected(int i) const
Returns true if the point with index 0 <= i < degree() is selected.
Definition vsegment.h:173
bool knotIsSelected() const
Returns true if the knot is selected.
Definition vsegment.h:181
VSegment * next() const
Returns a pointer to the next not deleted segment, if stored in a VSubpath.
void selectPoint(int i, bool select=true)
Selects the point with index 0 <= i < degree().
Definition vsegment.h:189
VSegment * prev() const
Returns a pointer to the previous not deleted segment, if stored in a VSubpath.
unsigned short degree() const
Returns the segment's degree, which is identical to the number of nodes.
Definition vsegment.h:77
const KoPoint & point(int i) const
Returns the segment's point with index 0 <= i < degree().
Definition vsegment.h:115
const KoPoint & knot() const
Returns the knot.
Definition vsegment.h:135
const VObjectList & objects() const
Read only access to the selected objects.
Definition vselection.h:136
void append()
Adds all objects to the selection.
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.
TQPtrList< VSegment > getSegments(const KoRect &rect)
Returns a list of segments that have at least one control point inside the specified rect.
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.
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
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
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
TDERadioAction * m_action
The tool's action object.
Definition vtool.h:309
bool isDragging() const
Returns the current dagging state.
Definition vtool.h:173
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