karbon

vpatterntool.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 "vpatterntool.h"
21
22#include <tqtoolbutton.h>
23#include <tqframe.h>
24#include <tqhbuttongroup.h>
25#include <tqlayout.h>
26#include <tqfileinfo.h>
27#include <tqlabel.h>
28#include <tqcursor.h>
29
30#include <kiconloader.h>
31#include <koIconChooser.h>
32#include <tdefiledialog.h>
33#include <tdemessagebox.h>
34
35#include <karbon_factory.h>
36#include <karbon_resourceserver.h>
37#include <karbon_view.h>
38#include <karbon_part.h>
39#include <render/vpainter.h>
40#include <render/vpainterfactory.h>
41#include <core/vselection.h>
42#include <core/vfill.h>
43#include <core/vstroke.h>
44#include <commands/vfillcmd.h>
45#include <commands/vstrokecmd.h>
46#include <widgets/vstrokefillpreview.h>
47
48VPatternWidget::VPatternWidget( TQPtrList<KoIconItem>* patterns, VTool*, TQWidget* parent )
49 : KDialogBase( parent, "", true, i18n( "Choose Pattern" ), Ok | Cancel ), m_pattern( 0 )
50{
51 TQWidget *base = new TQWidget( this );
52 TQVBoxLayout* layout = new TQVBoxLayout( base );
53 layout->addWidget( m_patternChooser = new KoIconChooser( TQSize( 32, 32 ), base ) );
54 layout->addWidget( m_buttonGroup = new TQHButtonGroup( base ) );
55 m_buttonGroup->insert( m_importPatternButton = new TQToolButton( m_buttonGroup ) );
56 m_buttonGroup->insert( m_deletePatternButton = new TQToolButton( m_buttonGroup ) );
57 m_patternChooser->setFixedSize( 180, 120 );
58 m_importPatternButton->setIconSet( SmallIconSet( "14_layer_newlayer" ) );
59 m_importPatternButton->setTextLabel( i18n( "Import" ) );
60 m_deletePatternButton->setIconSet( SmallIconSet("14_layer_deletelayer" ) );
61 m_deletePatternButton->setTextLabel( i18n( "Delete" ) );
62
63 m_buttonGroup->setInsideMargin( 3 );
64 m_importPatternButton->setEnabled( true );
65 m_deletePatternButton->setEnabled( false );
66
67 //setFrameStyle( Box | Sunken );
68 layout->setMargin( 3 );
69
70 connect( m_buttonGroup, TQ_SIGNAL( clicked( int ) ), this, TQ_SLOT( slotButtonClicked( int ) ) );
71 connect( m_patternChooser, TQ_SIGNAL( selected( KoIconItem* ) ), this, TQ_SLOT( patternSelected( KoIconItem* ) ) );
72
73 KoIconItem* item;
74 for( item = patterns->first(); item; item = patterns->next() )
75 m_patternChooser->addItem( item );
76 m_pattern = (VPattern*)patterns->first();
77
78 setMainWidget( base );
79} // VPatternWidget::VPatternWidget
80
81VPatternWidget::~VPatternWidget()
82{
83} // VPatternWidget::~VPatternWidget
84
85VPattern* VPatternWidget::selectedPattern()
86{
87 return m_pattern;
88} // VPatternWidget::selectedPattern
89
90void VPatternWidget::importPattern()
91{
92 VPattern* pattern = KarbonFactory::rServer()->addPattern( KFileDialog::getOpenFileName( TQString(),
93 "*.jpg *.gif *.png *.tif *.xpm *.bmp", this, i18n( "Choose Pattern to Add" ) ) );
94 if( pattern )
95 m_patternChooser->addItem( pattern );
96} // VPatternWidget::importPattern
97
98void VPatternWidget::deletePattern()
99{
100 m_patternChooser->removeItem( m_pattern );
101 KarbonFactory::rServer()->removePattern( m_pattern );
102 m_patternChooser->updateContents();
103 m_pattern = static_cast<VPattern*>( m_patternChooser->currentItem() );
104} // VPatternWidget::deletePattern
105
106void VPatternWidget::slotButtonClicked( int id )
107{
108 switch( id )
109 {
110 case 0: importPattern();
111 break;
112 case 1: deletePattern();
113 break;
114 }
115} // VPatternWidget::slotButtonClicked
116
117void VPatternWidget::patternSelected( KoIconItem* item )
118{
119 m_pattern = (VPattern*)item;
120 m_deletePatternButton->setEnabled( TQFileInfo( m_pattern->tilename() ).isWritable() );
121} // VPatternWidget::patternSelected
122
123VPatternTool::VPatternTool( KarbonView *view )
124 : VTool( view, "tool_pattern" ), m_state( normal ), m_handleSize( 3 ), m_active( false )
125{
126 TQPtrList<KoIconItem> patterns = KarbonFactory::rServer()->patterns();
127 m_optionsWidget = new VPatternWidget( &patterns, this );
128 registerTool( this );
129} // VPatternTool::VPatternTool
130
131VPatternTool::~VPatternTool()
132{
133 delete m_optionsWidget;
134} // VPatternTool::~VPatternTool
135
136void
138{
139 m_active = true;
140 m_state = normal;
142 view()->statusMessage()->setText( i18n( "Pattern" ) );
143 view()->setCursor( TQCursor( TQt::crossCursor ) );
144
145 if( view() )
146 {
147 // disable selection handles
148 view()->part()->document().selection()->showHandle( false );
149 // connect to the stroke-fill-preview to get notice when the stroke or fill gets selected
150 VStrokeFillPreview* preview = view()->strokeFillPreview();
151 if( preview )
152 {
153 connect( preview, TQ_SIGNAL( fillSelected() ), this, TQ_SLOT( targetChanged() ) );
154 connect( preview, TQ_SIGNAL( strokeSelected() ), this, TQ_SLOT( targetChanged() ) );
155 }
156 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
157 }
158}
159
160void
162{
163 m_active = false;
164
165 if( view() )
166 {
167 // enable selection handles
168 view()->part()->document().selection()->showHandle( true );
169 VStrokeFillPreview* preview = view()->strokeFillPreview();
170 if( preview )
171 {
172 disconnect( preview, TQ_SIGNAL( fillSelected() ), this, TQ_SLOT( targetChanged() ) );
173 disconnect( preview, TQ_SIGNAL( strokeSelected() ), this, TQ_SLOT( targetChanged() ) );
174 }
175 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
176 }
177}
178
179
180TQString
182{
183 TQString s = i18n( "<qt><b>Pattern tool:</b><br>" );
184 s += i18n( "<i>Click</i> on the pattern you want in the chooser.<br>" );
185 s += i18n( "<i>Click and drag</i> to choose the pattern vector.</qt>" );
186 s += i18n( "<i>Press i or Shift+i</i> to decrease or increase the handle size.<br>" );
187 return s;
188} // VPatternTool::contextHelp
189
190void VPatternTool::draw()
191{
192 if( ! view() || view()->part()->document().selection()->objects().count() == 0 )
193 return;
194
195 VPainter *painter = view()->painterFactory()->editpainter();
196 painter->setRasterOp( TQt::NotROP );
197
198 painter->setPen( TQt::DotLine );
199
200 // differentiate between moving a handle and creating a complete new vector
201 if( m_state == moveOrigin || m_state == moveVector )
202 {
203 painter->newPath();
204 painter->moveTo( m_fixed );
205 painter->lineTo( m_current );
206 painter->strokePath();
207 // draw the handle rects
208 painter->drawNode( m_fixed, m_handleSize );
209 painter->drawNode( m_current, m_handleSize );
210 }
211 else if( m_state == createNew )
212 {
213 painter->newPath();
214 painter->moveTo( first() );
215 painter->lineTo( m_current );
216 painter->strokePath();
217 // draw the handle rects
218 painter->drawNode( first(), m_handleSize );
219 painter->drawNode( m_current, m_handleSize );
220 }
221} // VPatternTool::draw
222
223bool
224VPatternTool::getPattern( VPattern &pattern )
225{
226 if( ! view() )
227 return false;
228
229 // determine if stroke of fill is selected for editing
230 //VStrokeFillPreview *preview = view()->strokeFillPreview();
231 //bool strokeSelected = ( preview && preview->strokeIsSelected() );
232 bool strokeSelected = false; // FIXME: stroke patterns don't work
233
234 VSelection* selection = view()->part()->document().selection();
235 if( selection->objects().count() != 1 )
236 return false;
237
238 VObject *obj = selection->objects().getFirst();
239 // get the pattern of the first selected object, if any
240 if( strokeSelected && obj->stroke()->type() == VStroke::patt )
241 pattern = obj->stroke()->pattern();
242 else if( ! strokeSelected && obj->fill()->type() == VFill::patt )
243 pattern = obj->fill()->pattern();
244 else
245 return false;
246
247 return true;
248}
249
250void
251VPatternTool::draw( VPainter* painter )
252{
253 if( ! m_active )
254 return;
255
256 if( m_state != normal )
257 return;
258
259 if( ! getPattern( m_pattern ) )
260 return;
261
262 KoPoint s = m_pattern.origin();
263 KoPoint e = m_pattern.vector();
264
265 // save the handle rects for later inside testing
266 m_origin = KoRect( s.x()-m_handleSize, s.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize );
267 m_vector = KoRect( e.x()-m_handleSize, e.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize );
268
269 painter->setPen( TQt::blue.light() );
270 painter->setBrush( TQt::blue.light() );
271 painter->setRasterOp( TQt::XorROP );
272
273 // draw the pattern vector
274 painter->newPath();
275 painter->moveTo( s );
276 painter->lineTo( e );
277 painter->strokePath();
278
279 // draw the handle rects
280 painter->drawNode( m_origin.center(), m_handleSize );
281 painter->drawNode( m_vector.center(), m_handleSize );
282}
283
284void
286{
287 if( m_state == normal )
288 return;
289
290 draw();
291
292 m_current = last();
293
294 draw();
295} // VPatternTool::mouseDrag
296
297void
299{
300 m_current = first();
301
302 // set the apropriate editing state
303 if( m_origin.contains( m_current ) )
304 {
305 m_state = moveOrigin;
306 m_fixed = m_vector.center();
307 }
308 else if( m_vector.contains( m_current ) )
309 {
310 m_state = moveVector;
311 m_fixed = m_origin.center();
312 }
313 else
314 m_state = createNew;
315} // VPatternTool::mouseButtonPress
316
317void
319{
320 m_state = normal;
321
322 if( view()->part()->document().selection()->objects().count() == 0 )
323 return;
324
325 // save old pattern position
326 VPattern oldPattern = m_pattern;
327
328 if( first() == last() )
329 {
330 if( showDialog() != TQDialog::Accepted )
331 return;
332 }
333
334 if( !m_optionsWidget->selectedPattern() )
335 {
336 KMessageBox::error( 0L, i18n( "Please select a pattern." ), "" );
337 return;
338 }
339
340 bool strokeSelected = false;
341
342 // determine the target from the stroke-fill-preview-widget
343 //VStrokeFillPreview* preview = view()->strokeFillPreview();
344 //if( preview && preview->strokeIsSelected() ) // FIXME: stroke patterns don't work
345 // strokeSelected = true;
346
347 // calculate a sane intial position for the new pattern
348 if( view()->part()->document().selection()->objects().count() == 1 )
349 {
350 VObject *obj = view()->part()->document().selection()->objects().getFirst();
351
352 if( ( ! strokeSelected && obj->fill()->type() != VFill::patt ) || (strokeSelected && obj->stroke()->type() != VStroke::patt ) )
353 {
354 KoRect bbox = obj->boundingBox();
355 oldPattern.setOrigin( bbox.bottomLeft() + 0.5*(bbox.topLeft()-bbox.bottomLeft()) );
356 oldPattern.setVector( bbox.bottomRight() + 0.5*(bbox.topRight()-bbox.bottomRight()) );
357 }
358 }
359
360 m_pattern = *m_optionsWidget->selectedPattern();
361
362 // use the old pattern position
363 m_pattern.setOrigin( oldPattern.origin() );
364 m_pattern.setVector( oldPattern.vector() );
365
366 if( ! strokeSelected )
367 {
368 VFill fill;
369 fill.pattern() = m_pattern;
370 fill.setType( VFill::patt );
371 view()->part()->addCommand(
372 new VFillCmd( &view()->part()->document(), fill, "14_pattern" ), true );
373 }
374 else
375 {
376 VStroke stroke;
377 stroke.pattern() = m_pattern;
378 stroke.setType( VStroke::patt );
379 view()->part()->addCommand(
380 new VStrokeCmd( &view()->part()->document(), &stroke, "14_pattern" ), true );
381 }
382} // VPatternTool::mouseButtonRelease
383
384void
386{
387 if( ! view() || m_state == normal )
388 return;
389
390 if( view()->part()->document().selection()->objects().count() == 0 )
391 {
392 draw();
393 return;
394 }
395
396 if( !m_optionsWidget->selectedPattern() )
397 {
398 draw();
399 KMessageBox::error( 0L, i18n( "Please select a pattern." ), "" );
400 return;
401 }
402 //m_pattern = *m_optionsWidget->selectedPattern();
403
404 if( m_state == moveOrigin )
405 m_pattern.setOrigin( last() );
406 else if( m_state == moveVector )
407 m_pattern.setVector( last() );
408 else if( m_state == createNew )
409 {
410 m_pattern.setOrigin( first() );
411 m_pattern.setVector( last() );
412 }
413
414 m_state = normal;
415
416 VStrokeFillPreview* preview = view()->strokeFillPreview();
417 if( ! preview )
418 return;
419
420 //if( ! preview->strokeIsSelected() ) // FIXME: stroke patterns don't work
421 {
422 VFill fill;
423 fill.pattern() = m_pattern;
424 fill.setType( VFill::patt );
425 view()->part()->addCommand(
426 new VFillCmd( &view()->part()->document(), fill, "14_pattern" ), true );
427 }
428 /*
429 else
430 {
431 VStroke stroke;
432 stroke.pattern() = m_pattern;
433 stroke.setType( VStroke::patt );
434 view()->part()->addCommand(
435 new VStrokeCmd( &view()->part()->document(), &stroke, "14_pattern" ), true );
436 }
437 */
438} // VPatternTool::mouseDragRelease
439
440void
442{
443 // Erase old object:
444 if( isDragging() )
445 draw();
446 m_state = normal;
447}
448
449bool
451{
452 return m_optionsWidget->exec() == TQDialog::Accepted;
453}
454
455void
456VPatternTool::setup( TDEActionCollection *collection )
457{
458 m_action = static_cast<TDERadioAction *>(collection -> action( name() ) );
459
460 if( m_action == 0 )
461 {
462 m_action = new TDERadioAction( i18n( "Pattern Tool" ), "14_pattern", TQt::SHIFT+TQt::Key_H, this, TQ_SLOT( activate() ), collection, name() );
463 m_action->setToolTip( i18n( "Pattern" ) );
464 m_action->setExclusiveGroup( "misc" );
465 //m_ownAction = true;
466 }
467}
468
469void
471{
472 if( !view() ) return;
473
474 // set a different cursor if mouse is inside the handle rects
475 if( m_origin.contains( last() ) || m_vector.contains( last() ) )
476 view()->setCursor( TQCursor( TQt::SizeAllCursor ) );
477 else
478 view()->setCursor( TQCursor( TQt::arrowCursor ) );
479}
480
481bool
482VPatternTool::keyReleased( TQt::Key key )
483{
484 // increase/decrease the handle size
485 switch( key )
486 {
487 case TQt::Key_I:
488 if( shiftPressed() )
489 m_handleSize++;
490 else if( m_handleSize > 3 )
491 m_handleSize--;
492 break;
493 default: return false;
494 }
495
496 if( view() )
497 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
498
499 return true;
500}
501
502void
503VPatternTool::targetChanged()
504{
505 if( view() )
506 view()->repaintAll( view()->part()->document().selection()->boundingBox() );
507}
508
509#include "vpatterntool.moc"
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
@ patt
gradient fill
Definition vfill.h:52
virtual const KoRect & boundingBox() const
Calculates the tightest bounding box around the object.
Definition vobject.h:111
virtual VFill * fill() const
Gets the object's actual fill.
Definition vobject.h:177
virtual VStroke * stroke() const
Gets the object's actual stroke.
Definition vobject.h:170
const VObjectList & objects() const
Read only access to the selected objects.
Definition vselection.h:136
void showHandle(bool handle=true)
Toggle selection handles on/off.
Definition vselection.h:166
@ patt
gradient as stroke
Definition vstroke.h:56
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 mouseButtonRelease()
Left mouse button release.
Definition vtool.h:195
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 void deactivate()
Deactivates the tool.
Definition vtool.h:83
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 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 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