1 /***************************************************************************
2  *   Copyright (C) 2004-2006 by David Saxton                               *
3  *   david@bluehaze.org                                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  ***************************************************************************/
10 
11 #include "cnitemgroup.h"
12 #include "canvasitemparts.h"
13 #include "dptext.h"
14 #include "canvasmanipulator.h"
15 #include "connector.h"
16 #include "flowcontainer.h"
17 #include "icndocument.h"
18 #include "itemview.h"
19 #include "mechanicsdocument.h"
20 #include "mechanicsgroup.h"
21 #include "mechanicsitem.h"
22 #include "node.h"
23 #include "nodegroup.h"
24 #include "picitem.h"
25 #include "resizeoverlay.h"
26 
27 #include "utils.h"
28 #include <cmath>
29 #include <cstdlib>
30 
31 #include <KConfigGroup>
32 #include <KSharedConfig>
33 
34 #include <QDebug>
35 #include <QCursor>
36 #include <QPainter>
37 #include <QTimer>
38 
39 // FIXME: This source file is HUUUGE!!!, contains numerous clases, should be broken down.
40 
41 
42 //BEGIN class CMManager
CMManager(ItemDocument * itemDocument)43 CMManager::CMManager( ItemDocument *itemDocument )
44 	: QObject()
45 {
46 	b_allowItemScroll = true;
47 	p_lastMouseOverResizeHandle = nullptr;
48 	m_canvasManipulator = nullptr;
49 	p_itemDocument = itemDocument;
50 	m_cmState = 0;
51 	p_lastMouseOverItem = nullptr;
52 	p_lastItemClicked = nullptr;
53 	m_drawAction = -1;
54 	m_allowItemScrollTmr = new QTimer(this);
55 	connect( m_allowItemScrollTmr, SIGNAL(timeout()), this, SLOT(slotAllowItemScroll()) );
56 
57 	KConfigGroup grGen = KSharedConfig::openConfig()->group("General");
58 	slotSetManualRoute( grGen.readEntry( "ManualRouting", false ) );
59 }
60 
61 
~CMManager()62 CMManager::~CMManager()
63 {
64 	delete m_allowItemScrollTmr;
65 	delete m_canvasManipulator;
66 
67 	const ManipulatorInfoList::iterator end = m_manipulatorInfoList.end();
68 	for ( ManipulatorInfoList::iterator it = m_manipulatorInfoList.begin(); it != end; ++it )
69 	{
70 		delete *it;
71 	}
72 	m_manipulatorInfoList.clear();
73 }
74 
75 
addManipulatorInfo(ManipulatorInfo * eventInfo)76 void CMManager::addManipulatorInfo( ManipulatorInfo *eventInfo )
77 {
78 	if ( eventInfo && !m_manipulatorInfoList.contains(eventInfo) ) {
79 		m_manipulatorInfoList.prepend(eventInfo);
80 	}
81 }
82 
83 
cancelCurrentManipulation()84 void CMManager::cancelCurrentManipulation()
85 {
86 	delete m_canvasManipulator;
87 	m_canvasManipulator = nullptr;
88 	setRepeatedAddId();
89 }
90 
91 
mousePressEvent(EventInfo eventInfo)92 void CMManager::mousePressEvent( EventInfo eventInfo )
93 {
94 	if (m_canvasManipulator)
95 	{
96 		if (m_canvasManipulator->mousePressedRepeat(eventInfo))
97 		{
98 			delete m_canvasManipulator;
99 			m_canvasManipulator = nullptr;
100 		}
101 		return;
102 	}
103 
104 	uint eventState=0;
105 	if (eventInfo.isRightClick)
106 		eventState |= CMManager::es_right_click;
107 
108 	if (eventInfo.ctrlPressed)
109 		eventState |= CMManager::es_ctrl_pressed;
110 
111 	uint itemType=0;
112 	uint cnItemType=0;
113 
114 	KtlQCanvasItem * qcanvasItem = eventInfo.qcanvasItemClickedOn;
115 
116 	if ( ! qcanvasItem ) itemType = it_none;
117 	else if ( dynamic_cast<Node*>(qcanvasItem) ) itemType = it_node;
118 	else if ( dynamic_cast<ConnectorLine*>(qcanvasItem) || dynamic_cast<Connector*>(qcanvasItem) )
119 		itemType = it_connector;
120 	else if ( dynamic_cast<PinItem*>(qcanvasItem) ) itemType = it_pin;
121 	else if ( dynamic_cast<ResizeHandle*>(qcanvasItem) ) itemType = it_resize_handle;
122 	else if ( DrawPart *drawPartClickedOn = dynamic_cast<DrawPart*>(qcanvasItem) )
123 	{
124 		itemType = it_drawpart;
125 
126 		if ( drawPartClickedOn->mousePressEvent(eventInfo) ) {
127 			p_lastItemClicked = drawPartClickedOn;
128 			return;
129 		}
130 
131 		if ( drawPartClickedOn->isMovable() )
132 			cnItemType |= CMManager::isi_isMovable;
133 	} else if ( MechanicsItem *p_mechanicsItemClickedOn = dynamic_cast<MechanicsItem*>(qcanvasItem) )
134 	{
135 		itemType = it_mechanics_item;
136 
137 		if ( p_mechanicsItemClickedOn->mousePressEvent(eventInfo) )
138 		{
139 			p_lastItemClicked = p_mechanicsItemClickedOn;
140 			return;
141 		}
142 	} else {
143 		if ( Widget *widget = dynamic_cast<Widget*>(qcanvasItem) )
144 			qcanvasItem = widget->parent();
145 
146 		if ( CNItem *cnItemClickedOn = dynamic_cast<CNItem*>(qcanvasItem) )
147 		{
148 			itemType = it_canvas_item;
149 
150 			if ( cnItemClickedOn->mousePressEvent(eventInfo) )
151 			{
152 				p_lastItemClicked = cnItemClickedOn;
153 				return;
154 			}
155 
156 			if ( cnItemClickedOn->isMovable() )
157 				cnItemType |= CMManager::isi_isMovable;
158 		}
159 	}
160 
161 // 	uint highestScore=0;
162 // 	ManipulatorInfo *best = nullptr;
163 	const ManipulatorInfoList::iterator end = m_manipulatorInfoList.end();
164 	for ( ManipulatorInfoList::iterator it = m_manipulatorInfoList.begin(); it != end && !m_canvasManipulator; ++it )
165 	{
166 		if ( (*it)->m_acceptManipulationPtr( eventState, m_cmState, itemType, cnItemType ) )
167 		{
168 			m_canvasManipulator = (*it)->m_createManipulatorPtr( p_itemDocument, this );
169 		}
170 	}
171 
172 	if (m_canvasManipulator)
173 	{
174 		if (m_canvasManipulator->mousePressedInitial(eventInfo))
175 		{
176 			delete m_canvasManipulator;
177 			m_canvasManipulator = nullptr;
178 		}
179 	}
180 }
181 
182 
mouseDoubleClickEvent(const EventInfo & eventInfo)183 void CMManager::mouseDoubleClickEvent( const EventInfo &eventInfo )
184 {
185 	if (m_canvasManipulator)
186 	{
187 		// Translate this into a repeat-click event
188 		if (m_canvasManipulator->mousePressedRepeat(eventInfo))
189 		{
190 			delete m_canvasManipulator;
191 			m_canvasManipulator = nullptr;
192 		}
193 		return;
194 	}
195 
196 	Item *item = dynamic_cast<Item*>(eventInfo.qcanvasItemClickedOn);
197 	if (item)
198 	{
199 		item->mouseDoubleClickEvent(eventInfo);
200 		return;
201 	}
202 
203 	Widget *widget = dynamic_cast<Widget*>(eventInfo.qcanvasItemClickedOn);
204 	if (widget)
205 	{
206 		widget->parent()->mouseDoubleClickEvent(eventInfo);
207 		return;
208 	}
209 }
210 
211 
mouseMoveEvent(const EventInfo & eventInfo)212 void CMManager::mouseMoveEvent( const EventInfo &eventInfo )
213 {
214 	if (m_canvasManipulator)
215 	{
216 		if (m_canvasManipulator->mouseMoved(eventInfo))
217 		{
218 			delete m_canvasManipulator;
219 			m_canvasManipulator = nullptr;
220 		}
221 		ItemView *itemView = dynamic_cast<ItemView*>(p_itemDocument->activeView());
222 		if (itemView)
223 			itemView->scrollToMouse(eventInfo.pos);
224 		return;
225 	}
226 
227 	//BEGIN
228 	KtlQCanvasItem *qcnItem = p_itemDocument->itemAtTop(eventInfo.pos);
229 	Item *item;
230 	Widget *widget = dynamic_cast<Widget*>(qcnItem);
231 	if (widget) item = widget->parent();
232 	else item = dynamic_cast<Item*>(qcnItem);
233 
234 	if ( p_lastMouseOverItem != (QPointer<Item>)item ) {
235 		QEvent event(QEvent::Leave);
236 
237 		if (p_lastMouseOverItem)
238 			p_lastMouseOverItem->leaveEvent(nullptr);
239 
240 		if (item) item->enterEvent(nullptr);
241 
242 		p_lastMouseOverItem = item;
243 	}
244 
245 	// If we clicked on an item, then continue to pass mouse events to that item until we release the mouse...
246 	if (p_lastItemClicked) {
247 		p_lastItemClicked->mouseMoveEvent(eventInfo);
248 	} else if (item) {
249 		item->mouseMoveEvent(eventInfo);
250 	}
251 	//END
252 
253 	updateCurrentResizeHandle( dynamic_cast<ResizeHandle*>(qcnItem) );
254 }
255 
256 
updateCurrentResizeHandle(ResizeHandle * resizeHandle)257 void CMManager::updateCurrentResizeHandle( ResizeHandle * resizeHandle )
258 {
259 	if ( p_lastMouseOverResizeHandle != (QPointer<ResizeHandle>)resizeHandle )
260 	{
261 		if (p_lastMouseOverResizeHandle)
262 			p_lastMouseOverResizeHandle->setHover(false);
263 		p_lastMouseOverResizeHandle = resizeHandle;
264 		if (resizeHandle)
265 			resizeHandle->setHover(true);
266 	}
267 }
268 
269 
mouseReleaseEvent(const EventInfo & eventInfo)270 void CMManager::mouseReleaseEvent( const EventInfo &eventInfo )
271 {
272 	// If it returns true, then it has finished its editing operation
273 	if ( m_canvasManipulator && m_canvasManipulator->mouseReleased(eventInfo) )
274 	{
275 		delete m_canvasManipulator;
276 		m_canvasManipulator = nullptr;
277 	}
278 
279 	if (p_lastItemClicked)
280 	{
281 		p_lastItemClicked->mouseReleaseEvent(eventInfo);
282 		p_lastItemClicked = nullptr;
283 	}
284 
285 	updateCurrentResizeHandle( dynamic_cast<ResizeHandle*>( p_itemDocument->itemAtTop(eventInfo.pos) ) );
286 }
287 
288 
wheelEvent(const EventInfo & eventInfo)289 void CMManager::wheelEvent( const EventInfo &eventInfo )
290 {
291 	bool accepted = false;
292 	if (b_allowItemScroll)
293 	{
294 		KtlQCanvasItem *qcnItem = p_itemDocument->itemAtTop(eventInfo.pos);
295 		Item *item;
296 		Widget *widget = dynamic_cast<Widget*>(qcnItem);
297 		if (widget)
298 			item = widget->parent();
299 		else	item = dynamic_cast<Item*>(qcnItem);
300 		if (item) accepted = item->wheelEvent(eventInfo);
301 	}
302 	if (!accepted)
303 	{
304 		// Only allow scrolling of items if we have not just been scrolling the canvas
305 		b_allowItemScroll = false;
306 		m_allowItemScrollTmr->stop();
307         m_allowItemScrollTmr->setSingleShot(true);
308 		m_allowItemScrollTmr->start(500 /*,true */ );
309 
310 		ItemView *itemView = dynamic_cast<ItemView*>(p_itemDocument->activeView());
311 		if (itemView)
312 		{
313 			itemView->cvbEditor()->setPassEventsToView(false);
314 			itemView->cvbEditor()->contentsWheelEvent( eventInfo.wheelEvent( 0, 0 ) );
315 			itemView->cvbEditor()->setPassEventsToView(true);
316 		}
317 	}
318 }
319 
320 
setDrawAction(int drawAction)321 void CMManager::setDrawAction( int drawAction )
322 {
323 	if ( m_drawAction == drawAction )
324 		return;
325 
326 	m_drawAction = drawAction;
327 	setCMState( cms_draw, (m_drawAction != -1) );
328 }
329 
330 
slotSetManualRoute(bool manualRoute)331 void CMManager::slotSetManualRoute( bool manualRoute )
332 {
333 	KConfigGroup grGen = KSharedConfig::openConfig()->group("General");
334 	grGen.writeEntry( "ManualRouting", manualRoute );
335 
336 	setCMState( cms_manual_route, manualRoute );
337 }
338 
339 
setCMState(CMState type,bool state)340 void CMManager::setCMState( CMState type, bool state )
341 {
342 	// Set or clear the correct bit
343 	state ? (m_cmState|=type) : (m_cmState&=(~type));
344 
345 	if ( type == CMManager::cms_manual_route )
346 		emit manualRoutingChanged(state);
347 }
348 
349 
setRepeatedAddId(const QString & repeatedId)350 void CMManager::setRepeatedAddId( const QString & repeatedId )
351 {
352 	m_repeatedItemId = repeatedId;
353 }
354 //END class CMManager
355 
356 
357 
358 //BEGIN class CanvasManipulator
CanvasManipulator(ItemDocument * itemDocument,CMManager * cmManager)359 CanvasManipulator::CanvasManipulator( ItemDocument *itemDocument, CMManager *cmManager )
360 {
361 	p_itemDocument = itemDocument;
362 	p_icnDocument = dynamic_cast<ICNDocument*>(itemDocument);
363 	p_mechanicsDocument = dynamic_cast<MechanicsDocument*>(itemDocument);
364 	p_canvas = p_itemDocument->canvas();
365 // 	b_connectorsAllowedRouting = true;
366 	p_selectList = p_itemDocument->selectList();
367 	p_cnItemSelectList = dynamic_cast<CNItemGroup*>(p_selectList);
368 	p_mechItemSelectList = dynamic_cast<MechanicsGroup*>(p_selectList);
369 	p_cnItemClickedOn = nullptr;
370 	p_cmManager = cmManager;
371 
372 	connect( itemDocument->canvas(), SIGNAL(resized( const QRect&, const QRect& )), this, SLOT(canvasResized( const QRect&, const QRect& )) );
373 }
374 
375 
~CanvasManipulator()376 CanvasManipulator::~CanvasManipulator()
377 {
378 }
379 
380 
snapPoint(QPoint point)381 QPoint CanvasManipulator::snapPoint( QPoint point )
382 {
383 	point /= 8;
384 	point *= 8;
385 	point += QPoint( 4, 4 );
386 	return point;
387 }
388 //END class CanvasManipulator
389 
390 
CMRepeatedItemAdd(ItemDocument * itemDocument,CMManager * cmManager)391 CMRepeatedItemAdd::CMRepeatedItemAdd( ItemDocument *itemDocument, CMManager *cmManager )
392 	: CanvasManipulator( itemDocument, cmManager )
393 {
394 }
395 
~CMRepeatedItemAdd()396 CMRepeatedItemAdd::~CMRepeatedItemAdd()
397 {
398 }
399 
construct(ItemDocument * itemDocument,CMManager * cmManager)400 CanvasManipulator* CMRepeatedItemAdd::construct( ItemDocument *itemDocument, CMManager *cmManager )
401 {
402 	return new CMRepeatedItemAdd(itemDocument,cmManager);
403 }
404 
manipulatorInfo()405 ManipulatorInfo *CMRepeatedItemAdd::manipulatorInfo()
406 {
407 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
408 	eventInfo->m_acceptManipulationPtr = CMRepeatedItemAdd::acceptManipulation;
409 	eventInfo->m_createManipulatorPtr = CMRepeatedItemAdd::construct;
410 	return eventInfo;
411 }
412 
acceptManipulation(uint,uint cmState,uint,uint)413 bool CMRepeatedItemAdd::acceptManipulation( uint /*eventState*/, uint cmState, uint /*itemType*/, uint /*cnItemType*/ )
414 {
415 	return (cmState & CMManager::cms_repeated_add);
416 }
417 
mousePressedRepeat(const EventInfo & eventInfo)418 bool CMRepeatedItemAdd::mousePressedRepeat( const EventInfo &eventInfo )
419 {
420 	return mousePressedInitial(eventInfo);
421 }
422 
mousePressedInitial(const EventInfo & eventInfo)423 bool CMRepeatedItemAdd::mousePressedInitial( const EventInfo &eventInfo )
424 {
425 	m_eventInfo = eventInfo;
426 	if (eventInfo.isRightClick)
427 	{
428 		p_cmManager->setCMState( CMManager::cms_repeated_add, false );
429 		return true;
430 	}
431 
432 	p_icnDocument->addItem( p_cmManager->repeatedItemId(), eventInfo.pos, true );
433 	p_itemDocument->requestStateSave();
434 	return false;
435 }
436 
437 
mouseMoved(const EventInfo &)438 bool CMRepeatedItemAdd::mouseMoved( const EventInfo &/*eventInfo*/ )
439 {
440 	return false;
441 }
442 
443 
mouseReleased(const EventInfo &)444 bool CMRepeatedItemAdd::mouseReleased( const EventInfo &/*eventInfo*/ )
445 {
446 	return false;
447 }
448 
449 
CMRightClick(ItemDocument * itemDocument,CMManager * cmManager)450 CMRightClick::CMRightClick( ItemDocument *itemDocument, CMManager *cmManager )
451 	: CanvasManipulator( itemDocument, cmManager )
452 {
453 }
454 
~CMRightClick()455 CMRightClick::~CMRightClick()
456 {
457 }
458 
construct(ItemDocument * itemDocument,CMManager * cmManager)459 CanvasManipulator* CMRightClick::construct( ItemDocument *itemDocument, CMManager *cmManager )
460 {
461 	return new CMRightClick(itemDocument,cmManager);
462 }
463 
manipulatorInfo()464 ManipulatorInfo *CMRightClick::manipulatorInfo()
465 {
466 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
467 // 	eventInfo->m_eventState.m_activate = CMManager::es_right_click;
468 	eventInfo->m_acceptManipulationPtr = CMRightClick::acceptManipulation;
469 	eventInfo->m_createManipulatorPtr = CMRightClick::construct;
470 	return eventInfo;
471 }
472 
acceptManipulation(uint eventState,uint,uint,uint)473 bool CMRightClick::acceptManipulation( uint eventState, uint /*cmState*/, uint /*itemType*/, uint /*cnItemType*/ )
474 {
475 	return eventState & CMManager::es_right_click;
476 }
477 
478 
mousePressedInitial(const EventInfo & eventInfo)479 bool CMRightClick::mousePressedInitial( const EventInfo &eventInfo )
480 {
481 	m_eventInfo = eventInfo;
482 	p_itemDocument->canvasRightClick( eventInfo.globalPos, eventInfo.qcanvasItemClickedOn );
483 	return true;
484 }
485 
486 
mouseMoved(const EventInfo &)487 bool CMRightClick::mouseMoved( const EventInfo &/*eventInfo*/ )
488 {
489 	return true;
490 }
491 
492 
mouseReleased(const EventInfo &)493 bool CMRightClick::mouseReleased( const EventInfo &/*eventInfo*/ )
494 {
495 	return true;
496 }
497 
498 
499 
500 //BEGIN class ConnectorDraw
ConnectorDraw(ItemDocument * itemDocument,CMManager * cmManager)501 ConnectorDraw::ConnectorDraw( ItemDocument *itemDocument, CMManager *cmManager )
502 	: CanvasManipulator( itemDocument, cmManager )
503 {
504 	p_startNode = nullptr;
505 	p_startConnector = nullptr;
506 	p_endNode = nullptr;
507 	p_endConnector = nullptr;
508 }
509 
510 
~ConnectorDraw()511 ConnectorDraw::~ConnectorDraw()
512 {
513 }
514 
515 
validConnectionColor()516 QColor ConnectorDraw::validConnectionColor()
517 {
518 	return QColor( 255, 166, 0 );
519 }
520 
521 
toValidPos(const QPoint & clickPos,Connector * clickedConnector) const522 QPoint ConnectorDraw::toValidPos( const QPoint & clickPos, Connector * clickedConnector ) const
523 {
524 	if ( !clickedConnector )
525 		return clickPos;
526 
527 	const QPointList pointList = clickedConnector->connectorPoints();
528 
529 	QPointList::const_iterator end = pointList.end();
530 
531 	double dl[] = { 0.5, 8.5, 11.5, 18.0, 23.0 }; // various distances rounded up of (0,0) cells, (0,1), etc
532 	for ( unsigned i = 0; i < 5; ++i )
533 	{
534 		for ( QPointList::const_iterator it = pointList.begin(); it != end; ++it )
535 		{
536 			if ( qpoint_distance( *it, clickPos ) <= dl[i] )
537 				return *it;
538 		}
539 	}
540 
541 	return clickPos;
542 }
543 
544 
toConnector(Node * node)545 Connector * ConnectorDraw::toConnector( Node * node )
546 {
547 	if ( !node || node->numCon( true, false ) < 3 )
548 		return nullptr;
549 
550 	return node->getAConnector();
551 }
552 
553 
grabEndStuff(KtlQCanvasItem * endItem,const QPoint & pos,bool posIsExact)554 void ConnectorDraw::grabEndStuff( KtlQCanvasItem * endItem, const QPoint & pos, bool posIsExact )
555 {
556 	if (!endItem)
557 		return;
558 
559 	CNItem * cnItem = dynamic_cast<CNItem*>(endItem);
560 	if ( cnItem && !posIsExact )
561 		p_endNode = cnItem->getClosestNode(pos);
562 	else
563 		p_endNode = dynamic_cast<Node*>(endItem);
564 
565 	if ( p_endNode && p_endNode->numCon( true, false ) > 2 )
566 	{
567 		p_endConnector = toConnector(p_endNode);
568 		p_endNode = nullptr;
569 	}
570 
571 	// If the endItem is a node, we have to finish exactly on the end when posIsExact is true
572 	if ( posIsExact && p_endNode && (p_endNode->x() != pos.x() || p_endNode->y() != pos.y()) )
573 		p_endNode = nullptr;
574 
575 	if (!p_endConnector)
576 		p_endConnector = dynamic_cast<Connector*>(endItem);
577 }
578 //END class ConnectorDraw
579 
580 
581 //BEGIN class CMAutoConnector
CMAutoConnector(ItemDocument * itemDocument,CMManager * cmManager)582 CMAutoConnector::CMAutoConnector( ItemDocument *itemDocument, CMManager *cmManager )
583 	: ConnectorDraw( itemDocument, cmManager )
584 {
585 	m_connectorLine = nullptr;
586 	p_startNode = nullptr;
587 	p_startConnector = nullptr;
588 }
589 
~CMAutoConnector()590 CMAutoConnector::~CMAutoConnector()
591 {
592 	delete m_connectorLine;
593 
594 }
595 
construct(ItemDocument * itemDocument,CMManager * cmManager)596 CanvasManipulator* CMAutoConnector::construct( ItemDocument *itemDocument, CMManager *cmManager )
597 {
598 	return new CMAutoConnector(itemDocument,cmManager);
599 }
600 
manipulatorInfo()601 ManipulatorInfo *CMAutoConnector::manipulatorInfo()
602 {
603 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
604 	eventInfo->m_acceptManipulationPtr = CMAutoConnector::acceptManipulation;
605 	eventInfo->m_createManipulatorPtr = CMAutoConnector::construct;
606 	return eventInfo;
607 }
608 
acceptManipulation(uint,uint cmState,uint itemType,uint)609 bool CMAutoConnector::acceptManipulation( uint /*eventState*/, uint cmState, uint itemType, uint /*cnItemType*/ )
610 {
611 	return (itemType & (CMManager::it_node | CMManager::it_connector)) && !(cmState & CMManager::cms_manual_route);
612 }
613 
mousePressedInitial(const EventInfo & eventInfo)614 bool CMAutoConnector::mousePressedInitial( const EventInfo &eventInfo )
615 {
616 	m_eventInfo = eventInfo;
617 
618 	p_startNode = dynamic_cast<Node*>(eventInfo.qcanvasItemClickedOn);
619 
620 	if (p_startNode)
621 	{
622 		m_eventInfo.pos = m_prevPos = p_icnDocument->gridSnap( QPoint( (int)p_startNode->x(), (int)p_startNode->y() ) );
623 		if (p_startNode->numCon( true, false ) > 2)
624 		{
625 			p_startConnector = toConnector(p_startNode);
626 			p_startNode = nullptr;
627 		}
628 	} else if ((p_startConnector = dynamic_cast<Connector*>(eventInfo.qcanvasItemClickedOn) ))
629 	{
630 // 		startConnectorPoint = m_eventInfo.pos = m_prevPos = p_icnDocument->gridSnap(m_eventInfo.pos);
631 		startConnectorPoint = m_eventInfo.pos = m_prevPos = toValidPos( m_eventInfo.pos, p_startConnector );
632 	} else return true;
633 
634 	p_icnDocument->unselectAll();
635 
636 	delete m_connectorLine;
637 	m_connectorLine = new KtlQCanvasLine(p_canvas);
638 	m_connectorLine->setPen( QColor(0,0,0) );
639 	m_connectorLine->setZ( ItemDocument::Z::ConnectorCreateLine );
640 	m_connectorLine->show();
641 	return false;
642 }
643 
644 
mouseMoved(const EventInfo & eventInfo)645 bool CMAutoConnector::mouseMoved( const EventInfo &eventInfo )
646 {
647 	const QPoint pos = eventInfo.pos;
648 
649 	int newX = p_icnDocument->gridSnap( pos.x() );
650 	int newY = p_icnDocument->gridSnap( pos.y() );
651 
652 	bool movedFlag = false;
653 
654 	if ( newX != m_prevPos.x() )
655 	{
656 		m_prevPos.setX(newX);
657 		movedFlag = true;
658 	}
659 
660 	if ( newY != m_prevPos.y() )
661 	{
662 		m_prevPos.setY(newY);
663 		movedFlag = true;
664 	}
665 
666 	m_connectorLine->setPoints( m_eventInfo.pos.x(), m_eventInfo.pos.y(), newX, newY );
667 
668 	if (movedFlag) {
669 		KtlQCanvasItem *startItem = nullptr;
670 		if (p_startNode)
671 			startItem = p_startNode;
672 		else if (p_startConnector)
673 			startItem = p_startConnector;
674 
675 		KtlQCanvasItem *endItem = p_icnDocument->itemAtTop( QPoint( newX, newY ) );
676 		if ( CNItem * cni = dynamic_cast<CNItem*>(endItem) )
677 			endItem = cni->getClosestNode( QPoint( newX, newY ) );
678 
679 		bool validLine = p_icnDocument->canConnect( startItem, endItem );
680 		m_connectorLine->setPen( validLine ? validConnectionColor() : Qt::black );
681 	}
682 	return false;
683 }
684 
685 
mouseReleased(const EventInfo & eventInfo)686 bool CMAutoConnector::mouseReleased( const EventInfo &eventInfo )
687 {
688 	const QPoint pos = eventInfo.pos;
689 
690 	QPoint end = m_connectorLine->endPoint();
691 	delete m_connectorLine;
692 	m_connectorLine = nullptr;
693 
694 	KtlQCanvasItem *qcanvasItem = p_icnDocument->itemAtTop(end);
695 	if ( !qcanvasItem )
696 		return true;
697 
698 	grabEndStuff( qcanvasItem, pos, false );
699 
700 	if (p_startConnector)
701 	{
702 		if (p_endConnector) {
703 			if ( !p_icnDocument->createConnector( p_endConnector, p_startConnector, p_icnDocument->gridSnap(pos), startConnectorPoint ) )
704 				return true;
705 		} else if (p_endNode) {
706 			if ( !p_icnDocument->createConnector( p_endNode, p_startConnector, startConnectorPoint ) )
707 				return true;
708 		} else	return true;
709 	} else if (p_startNode) {
710 		if (p_endConnector)
711 		{
712 			if ( !p_icnDocument->createConnector( p_startNode, p_endConnector, p_icnDocument->gridSnap(pos) ) )
713 				return true;
714 		} else if (p_endNode) {
715 			if ( !p_icnDocument->createConnector( p_startNode, p_endNode ) )
716 				return true;
717 		} else	return true;
718 	} else return true;
719 
720 	p_itemDocument->requestStateSave();
721 	return true;
722 }
723 //END class CMAutoConnector
724 
725 
726 
727 //BEGIN class CMManualConnector
CMManualConnector(ItemDocument * itemDocument,CMManager * cmManager)728 CMManualConnector::CMManualConnector( ItemDocument *itemDocument, CMManager *cmManager )
729 	: ConnectorDraw( itemDocument, cmManager )
730 {
731 	m_manualConnectorDraw = nullptr;
732 }
733 
~CMManualConnector()734 CMManualConnector::~CMManualConnector()
735 {
736 	delete m_manualConnectorDraw;
737 }
738 
construct(ItemDocument * itemDocument,CMManager * cmManager)739 CanvasManipulator* CMManualConnector::construct( ItemDocument *itemDocument, CMManager *cmManager )
740 {
741 	return new CMManualConnector(itemDocument,cmManager);
742 }
743 
manipulatorInfo()744 ManipulatorInfo *CMManualConnector::manipulatorInfo()
745 {
746 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
747 	eventInfo->m_acceptManipulationPtr = CMManualConnector::acceptManipulation;
748 	eventInfo->m_createManipulatorPtr = CMManualConnector::construct;
749 	return eventInfo;
750 }
751 
acceptManipulation(uint,uint cmState,uint itemType,uint)752 bool CMManualConnector::acceptManipulation( uint /*eventState*/, uint cmState, uint itemType, uint /*cnItemType*/ )
753 {
754 	return (itemType & (CMManager::it_node | CMManager::it_connector)) && (cmState & CMManager::cms_manual_route);
755 }
756 
757 
mousePressedInitial(const EventInfo & eventInfo)758 bool CMManualConnector::mousePressedInitial( const EventInfo &eventInfo )
759 {
760 	if ( eventInfo.isRightClick ) return true;
761 
762 	m_eventInfo = eventInfo;
763 
764 	p_icnDocument->unselectAll();
765 
766 	QPoint sp;
767 
768 	if ( (p_startNode = dynamic_cast<Node*>(eventInfo.qcanvasItemClickedOn)) )
769 	{
770 		sp.setX( (int)p_startNode->x() );
771 		sp.setY( (int)p_startNode->y() );
772 		if ( p_startNode->numCon( true, false ) > 2 )
773 		{
774 			p_startConnector = toConnector(p_startNode);
775 			p_startNode = nullptr;
776 		}
777 	}
778 	else
779 	{
780 		p_startConnector = dynamic_cast<Connector*>(eventInfo.qcanvasItemClickedOn);
781 		sp = toValidPos( eventInfo.pos, p_startConnector );
782 	}
783 	startConnectorPoint = sp;
784 
785 	if (m_manualConnectorDraw)
786 		delete m_manualConnectorDraw;
787 	m_manualConnectorDraw = new ManualConnectorDraw( p_icnDocument, sp );
788 	return false;
789 }
790 
791 
mousePressedRepeat(const EventInfo & eventInfo)792 bool CMManualConnector::mousePressedRepeat( const EventInfo &eventInfo )
793 {
794 	m_eventInfo = eventInfo;
795 	if ( eventInfo.isRightClick ) {
796 		return true;
797 	}
798 	m_manualConnectorDraw->mouseClicked( p_icnDocument->gridSnap(m_eventInfo.pos) );
799 	return false;
800 }
801 
802 
mouseMoved(const EventInfo & eventInfo)803 bool CMManualConnector::mouseMoved( const EventInfo &eventInfo )
804 {
805 	if ( !m_manualConnectorDraw )
806 		return true;
807 
808 	const QPoint pos = eventInfo.pos;
809 
810     int newX = p_icnDocument->gridSnap( pos.x() );
811 	int newY = p_icnDocument->gridSnap( pos.y() );
812 
813 	bool movedFlag = false;
814 
815 	if ( newX != m_prevPos.x() )
816 	{
817 		m_prevPos.setX(newX);
818 		movedFlag = true;
819 	}
820 
821 	if ( newY != m_prevPos.y() )
822 	{
823 		m_prevPos.setY(newY);
824 		movedFlag = true;
825 	}
826 
827 	if ( movedFlag )
828 	{
829 		KtlQCanvasItem *startItem = nullptr;
830 		if (p_startNode)
831 			startItem = p_startNode;
832 		else if (p_startConnector)
833 			startItem = p_startConnector;
834 
835 		KtlQCanvasItem * endItem = p_icnDocument->itemAtTop( QPoint( newX, newY ) );
836 
837 		// If the endItem is a node, we have to finish exactly on the end.
838 		if ( Node * node = dynamic_cast<Node*>(endItem) )
839 		{
840 			if ( node->x() != newX || node->y() != newY )
841 				endItem = nullptr;
842 		}
843 
844 		bool validLine = p_icnDocument->canConnect( startItem, endItem );
845 
846 		m_manualConnectorDraw->setColor( validLine ? validConnectionColor() : Qt::black );
847 		m_manualConnectorDraw->mouseMoved( QPoint( newX, newY ) );
848 	}
849 
850 	return false;
851 }
852 
853 
mouseReleased(const EventInfo & eventInfo)854 bool CMManualConnector::mouseReleased( const EventInfo &eventInfo )
855 {
856 	if (!m_manualConnectorDraw) return true;
857 
858 	QPoint pos = p_icnDocument->gridSnap(eventInfo.pos);
859 
860 	grabEndStuff( m_manualConnectorDraw->mouseClicked(pos), pos, true );
861 
862 	if ( !p_endNode && !p_endConnector )
863 		return false;
864 
865 	// Create the points that define the manual route
866 	QPointList list = m_manualConnectorDraw->pointList();
867 	delete m_manualConnectorDraw;
868 	m_manualConnectorDraw = nullptr;
869 
870 	if (p_startConnector)
871 	{
872 		if (p_endConnector)
873 		{
874 			if ( !p_icnDocument->createConnector( p_endConnector, p_startConnector, p_icnDocument->gridSnap(pos), startConnectorPoint, &list ) )
875 				return true;
876 		} else // if (p_endNode)
877 		{
878 			if ( !p_icnDocument->createConnector( p_endNode, p_startConnector, startConnectorPoint, &list ) )
879 				return true;
880 		}
881 	} else if (p_startNode) {
882 		if (p_endConnector)
883 		{
884 			if ( !p_icnDocument->createConnector( p_startNode, p_endConnector, p_icnDocument->gridSnap(pos), &list ) )
885 				return true;
886 		} else // if (p_endNode)
887 		{
888 			if ( !p_icnDocument->createConnector( p_startNode, p_endNode, &list ) )
889 				return true;
890 		}
891 	} else return true;
892 
893 	p_itemDocument->requestStateSave();
894 	return true;
895 }
896 //END class CMManualConnector
897 
898 
899 //BEGIN class CMItemMove
CMItemMove(ItemDocument * itemDocument,CMManager * cmManager)900 CMItemMove::CMItemMove( ItemDocument *itemDocument, CMManager *cmManager )
901 	: CanvasManipulator( itemDocument, cmManager )
902 {
903 	p_flowContainerCandidate = nullptr;
904 	m_bItemsSnapToGrid = false;
905 }
906 
~CMItemMove()907 CMItemMove::~CMItemMove()
908 {
909 }
910 
construct(ItemDocument * itemDocument,CMManager * cmManager)911 CanvasManipulator* CMItemMove::construct( ItemDocument *itemDocument, CMManager *cmManager )
912 {
913 	return new CMItemMove(itemDocument,cmManager);
914 }
915 
manipulatorInfo()916 ManipulatorInfo *CMItemMove::manipulatorInfo()
917 {
918 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
919 	eventInfo->m_acceptManipulationPtr = CMItemMove::acceptManipulation;
920 	eventInfo->m_createManipulatorPtr = CMItemMove::construct;
921 	return eventInfo;
922 }
923 
acceptManipulation(uint eventState,uint,uint itemType,uint cnItemType)924 bool CMItemMove::acceptManipulation( uint eventState, uint /*cmState*/, uint itemType, uint cnItemType )
925 {
926 	return ((itemType & CMManager::it_canvas_item) || (itemType & CMManager::it_drawpart)) && (cnItemType & CMManager::isi_isMovable) && !(eventState & CMManager::es_right_click);
927 }
928 
929 
mousePressedInitial(const EventInfo & eventInfo)930 bool CMItemMove::mousePressedInitial( const EventInfo &eventInfo )
931 {
932 	m_eventInfo = eventInfo;
933 	m_prevPos = eventInfo.pos;
934 
935 	Item *item = dynamic_cast<Item*>(eventInfo.qcanvasItemClickedOn);
936 
937 	if (!item) return true;
938 
939 	if ( !p_selectList->contains(item) )
940 	{
941 		if (!eventInfo.ctrlPressed)
942 			p_itemDocument->unselectAll();
943 
944 		p_itemDocument->select(item);
945 	} else if (m_eventInfo.ctrlPressed)
946 		p_itemDocument->unselect(item);
947 
948 	if ( p_selectList->isEmpty() )
949 		return true;
950 
951 	// We want to allow dragging into FlowContainers if this is a FlowView
952 	p_flowContainerCandidate = nullptr;
953 	{
954 		const ItemList &itemList = p_icnDocument->itemList();
955 		const ItemList::const_iterator ciEnd = itemList.end();
956 		for ( ItemList::const_iterator it = itemList.begin(); it != ciEnd; ++it )
957 		{
958 			if ( FlowContainer *flowContainer = dynamic_cast<FlowContainer*>((Item*)*it) )
959 				flowContainer->setFullBounds(true);
960 		}
961 	}
962 
963 	ItemList itemList = p_cnItemSelectList->items(false);
964 	itemList.removeAll((Item*)nullptr);
965 
966 	m_bItemsSnapToGrid = false;
967 	const ItemList::iterator itemListEnd = itemList.end();
968 	for ( ItemList::iterator it = itemList.begin(); it != itemListEnd; ++it )
969 	{
970 		CNItem *cnItem = dynamic_cast<CNItem*>((Item*)*it);
971 		if ( !cnItem || !cnItem->canvas() )
972 			continue;
973 
974 		m_bItemsSnapToGrid = true;
975 	}
976 
977 	if ( m_bItemsSnapToGrid )
978 		m_prevSnapPoint = this->snapPoint( m_prevPos );
979 	else	m_prevSnapPoint = m_prevPos;
980 
981 	ConnectorList fixedConnectors;
982 	p_icnDocument->getTranslatable( itemList, &fixedConnectors, &m_translatableConnectors, &m_translatableNodeGroups );
983 
984 	const ConnectorList::iterator fixedConnectorsEnd = fixedConnectors.end();
985 	for ( ConnectorList::iterator it = fixedConnectors.begin(); it != fixedConnectorsEnd; ++it )
986 		(*it)->setSemiHidden(true);
987 
988 	p_flowContainerCandidate = p_icnDocument->flowContainer(eventInfo.pos);
989 
990 	return false;
991 }
992 
993 
canvasResized(const QRect &,const QRect &)994 void CMItemMove::canvasResized( const QRect & /*oldSize*/, const QRect & /*newSize*/ )
995 {
996 	//QPoint delta = oldSize.topLeft() - newSize.topLeft(); // 2017.10.01 - comment out unused variable
997 
998 // 	scrollCanvasToSelection();
999 
1000 // 	QCursor::setPos( QCursor::pos() + delta );
1001 // 	m_prevPos += delta;
1002 // 	m_prevSnapPoint += delta;
1003 }
1004 
1005 
scrollCanvasToSelection()1006 void CMItemMove::scrollCanvasToSelection()
1007 {
1008 	QRect bound;
1009 	ItemList itemList = p_cnItemSelectList->items(false);
1010 	itemList.removeAll((Item*)nullptr);
1011 	const ItemList::iterator itemListEnd = itemList.end();
1012 	for ( ItemList::iterator it = itemList.begin(); it != itemListEnd; ++it )
1013 		bound |= (*it)->boundingRect();
1014 
1015 	QPoint scrollToPos = m_prevPos;
1016 	if ( m_dx < 0 ) {
1017 		// Scrolling left
1018 		scrollToPos -= QPoint( bound.left(), 0 );
1019 	} else {
1020 		// Scrolling right
1021 		scrollToPos += QPoint( bound.right(), 0 );
1022 	}
1023 
1024 	if ( m_dy < 0 ) {
1025 		// Scrolling up
1026 		scrollToPos -= QPoint( 0, bound.top() );
1027 	} else {
1028 		// Scrolling right
1029 		scrollToPos += QPoint( 0, bound.bottom() );
1030 	}
1031 
1032 	ItemView *itemView = dynamic_cast<ItemView*>(p_itemDocument->activeView());
1033 	if (itemView)
1034 		itemView->scrollToMouse( scrollToPos );
1035 }
1036 
1037 
mouseMoved(const EventInfo & eventInfo)1038 bool CMItemMove::mouseMoved( const EventInfo &eventInfo )
1039 {
1040 	QPoint pos = eventInfo.pos;
1041 
1042 	QPoint snapPoint = pos;
1043 	if ( m_bItemsSnapToGrid )
1044 		snapPoint = this->snapPoint( snapPoint );
1045 
1046 	int dx = snapPoint.x() - m_prevSnapPoint.x();
1047 	int dy = snapPoint.y() - m_prevSnapPoint.y();
1048 
1049 	m_dx = dx;
1050 	m_dy = dy;
1051 
1052    	const ItemList itemList = p_cnItemSelectList->items();
1053 	const ItemList::const_iterator end = itemList.end();
1054 
1055 	for ( ItemList::const_iterator it = itemList.begin(); it != end; ++it )
1056 	{
1057 		if ( !*it || !(*it)->isMovable() )
1058 			continue;
1059 
1060 		//QRect oldRect = (*it)->boundingRect(); // 2017.10.01 - comment out unused variable
1061 		(*it)->moveBy( dx, dy );
1062 		//QRect newRect = (*it)->boundingRect();
1063 		//QRect merged = oldRect | newRect; // 2017.10.01 - comment out unused variable
1064 	}
1065 
1066 	if ( (dx != 0) || (dy != 0) )
1067 	{
1068 		const ConnectorList::iterator frEnd = m_translatableConnectors.end();
1069 		for ( ConnectorList::iterator it = m_translatableConnectors.begin(); it != frEnd; ++it )
1070 			(*it)->translateRoute( dx, dy );
1071 
1072 		const NodeGroupList::iterator end = m_translatableNodeGroups.end();
1073 		for ( NodeGroupList::iterator it = m_translatableNodeGroups.begin(); it != end; ++it )
1074 			(*it)->translate( dx, dy );
1075 	}
1076 
1077 	FlowContainer *fc = p_icnDocument->flowContainer(pos);
1078 	if ( fc != p_flowContainerCandidate )
1079 	{
1080 		if ( p_flowContainerCandidate )
1081 		{
1082 			p_flowContainerCandidate->setSelected(false);
1083 			p_flowContainerCandidate = nullptr;
1084 		}
1085 	}
1086 
1087 	if (fc)
1088 	{
1089 		p_flowContainerCandidate = fc;
1090 		p_flowContainerCandidate->setSelected(true);
1091 	}
1092 
1093 	p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems );
1094 	p_canvas->update();
1095 	m_prevPos = pos;
1096 	m_prevSnapPoint = snapPoint;
1097 
1098 // 	scrollCanvasToSelection();
1099 
1100 	return false;
1101 }
1102 
1103 
mouseReleased(const EventInfo & eventInfo)1104 bool CMItemMove::mouseReleased( const EventInfo &eventInfo )
1105 {
1106 	// Is the release event from a right click (which rotates items)?
1107 	if ( eventInfo.isRightClick || eventInfo.isMiddleClick )
1108 		return false;
1109 
1110 	QStringList itemIDs;
1111 
1112 	const ItemList itemList = p_cnItemSelectList->items();
1113 	const ItemList::const_iterator ilEnd = itemList.end();
1114 	for ( ItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it )
1115 	{
1116 		if (*it) itemIDs.append( (*it)->id() );
1117 	}
1118 
1119 	//const QPoint pos = eventInfo.pos; // 2017.10.10 - comment out unused variable
1120 
1121 	// And make sure all connectors are properly shown
1122 	const ConnectorList &connectorList = p_icnDocument->connectorList();
1123 	const ConnectorList::const_iterator conEnd = connectorList.end();
1124 	for ( ConnectorList::const_iterator it = connectorList.begin(); it != conEnd; ++it )
1125 	{
1126 		(*it)->setSemiHidden(false);
1127 	}
1128 
1129 	if (p_flowContainerCandidate)
1130 	{
1131 		for ( ItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it )
1132 			p_flowContainerCandidate->addChild(*it);
1133 
1134 		p_flowContainerCandidate->setSelected(false);
1135 		p_flowContainerCandidate = nullptr;
1136 	} else {
1137 		for ( ItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it )
1138 			(*it)->setParentItem(nullptr);
1139 	}
1140 
1141 	// And disable the FlowContainers again...
1142 	const ItemList &cnItemList = p_icnDocument->itemList();
1143 	const ItemList::const_iterator end = cnItemList.end();
1144 	for ( ItemList::const_iterator it = cnItemList.begin(); it != end; ++it )
1145 	{
1146 		if ( FlowContainer *flowContainer = dynamic_cast<FlowContainer*>((Item*)*it) )
1147 			flowContainer->setFullBounds(false);
1148 	}
1149 
1150 	if (p_icnDocument) p_icnDocument->requestRerouteInvalidatedConnectors();
1151 
1152 	if ( m_eventInfo.pos != eventInfo.pos ) p_itemDocument->requestStateSave();
1153 
1154 	p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems );
1155 
1156 	return true;
1157 }
1158 
1159 
mousePressedRepeat(const EventInfo & info)1160 bool CMItemMove::mousePressedRepeat( const EventInfo & info )
1161 {
1162 	if ( info.isRightClick )
1163 		p_cnItemSelectList->slotRotateCW();
1164 	else if ( info.isMiddleClick )
1165 		p_cnItemSelectList->flipHorizontally();
1166 
1167 	return false;
1168 }
1169 //END class CMItemMove
1170 
1171 
CMItemResize(ItemDocument * itemDocument,CMManager * cmManager)1172 CMItemResize::CMItemResize( ItemDocument *itemDocument, CMManager *cmManager )
1173 	: CanvasManipulator( itemDocument, cmManager )
1174 {
1175 }
1176 
~CMItemResize()1177 CMItemResize::~CMItemResize()
1178 {
1179 }
1180 
construct(ItemDocument * itemDocument,CMManager * cmManager)1181 CanvasManipulator* CMItemResize::construct( ItemDocument *itemDocument, CMManager *cmManager )
1182 {
1183 	return new CMItemResize(itemDocument,cmManager);
1184 }
1185 
manipulatorInfo()1186 ManipulatorInfo *CMItemResize::manipulatorInfo()
1187 {
1188 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
1189 // 	eventInfo->m_itemType.m_activate = CMManager::it_canvas_item;
1190 	eventInfo->m_acceptManipulationPtr = CMItemResize::acceptManipulation;
1191 	eventInfo->m_createManipulatorPtr = CMItemResize::construct;
1192 	return eventInfo;
1193 }
1194 
acceptManipulation(uint eventState,uint,uint itemType,uint)1195 bool CMItemResize::acceptManipulation( uint eventState, uint /*cmState*/, uint itemType, uint /*cnItemType*/ )
1196 {
1197 	return (itemType & CMManager::it_resize_handle) && !(eventState & CMManager::es_right_click);
1198 }
1199 
1200 
mousePressedInitial(const EventInfo & eventInfo)1201 bool CMItemResize::mousePressedInitial( const EventInfo &eventInfo )
1202 {
1203 	m_eventInfo = eventInfo;
1204 	p_resizeHandle = dynamic_cast<ResizeHandle*>(eventInfo.qcanvasItemClickedOn);
1205 	m_rh_dx = p_resizeHandle->x()-eventInfo.pos.x();
1206 	m_rh_dy = p_resizeHandle->y()-eventInfo.pos.y();
1207 	return false;
1208 }
1209 
1210 
mouseMoved(const EventInfo & eventInfo)1211 bool CMItemResize::mouseMoved( const EventInfo &eventInfo )
1212 {
1213 	int _x = int(m_rh_dx + eventInfo.pos.x());
1214 	int _y = int(m_rh_dy + eventInfo.pos.y());
1215 
1216 	// Shift pressed == snap to grid
1217 	if ( eventInfo.shiftPressed )
1218 	{
1219 		_x = snapToCanvas(_x);
1220 		_y = snapToCanvas(_y);
1221 	}
1222 
1223 	p_resizeHandle->moveRH( _x, _y );
1224 	return false;
1225 }
1226 
1227 
mouseReleased(const EventInfo &)1228 bool CMItemResize::mouseReleased( const EventInfo &/*eventInfo*/ )
1229 {
1230 	if (p_icnDocument)
1231 		p_icnDocument->requestRerouteInvalidatedConnectors();
1232 	p_itemDocument->requestStateSave();
1233 	return true;
1234 }
1235 
1236 
CMMechItemMove(ItemDocument * itemDocument,CMManager * cmManager)1237 CMMechItemMove::CMMechItemMove( ItemDocument *itemDocument, CMManager *cmManager )
1238 	: CanvasManipulator( itemDocument, cmManager )
1239 {
1240 }
1241 
~CMMechItemMove()1242 CMMechItemMove::~CMMechItemMove()
1243 {
1244 }
1245 
construct(ItemDocument * itemDocument,CMManager * cmManager)1246 CanvasManipulator* CMMechItemMove::construct( ItemDocument *itemDocument, CMManager *cmManager )
1247 {
1248 	return new CMMechItemMove(itemDocument,cmManager);
1249 }
1250 
manipulatorInfo()1251 ManipulatorInfo *CMMechItemMove::manipulatorInfo()
1252 {
1253 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
1254 // 	eventInfo->m_itemType.m_activate = CMManager::it_canvas_item;
1255 	eventInfo->m_acceptManipulationPtr = CMMechItemMove::acceptManipulation;
1256 	eventInfo->m_createManipulatorPtr = CMMechItemMove::construct;
1257 	return eventInfo;
1258 }
1259 
acceptManipulation(uint eventState,uint,uint itemType,uint)1260 bool CMMechItemMove::acceptManipulation( uint eventState, uint /*cmState*/, uint itemType, uint /*cnItemType*/ )
1261 {
1262 	return ((itemType & CMManager::it_mechanics_item) || (itemType & CMManager::it_drawpart)) && !(eventState & CMManager::es_right_click);
1263 }
1264 
1265 
mousePressedInitial(const EventInfo & eventInfo)1266 bool CMMechItemMove::mousePressedInitial( const EventInfo &eventInfo )
1267 {
1268 	m_eventInfo = eventInfo;
1269 	m_prevPos = eventInfo.pos;
1270 
1271 	Item *item = dynamic_cast<Item*>(eventInfo.qcanvasItemClickedOn);
1272 	if (!item)
1273 		return true;
1274 
1275 	MechanicsItem *mechItem = dynamic_cast<MechanicsItem*>(eventInfo.qcanvasItemClickedOn);
1276 
1277 	if (mechItem) m_prevClickedOnSM = mechItem->selectionMode();
1278 
1279 	if (eventInfo.shiftPressed)
1280 	{
1281 		p_mechanicsDocument->unselectAll();
1282 		p_mechanicsDocument->select(item);
1283 		if (mechItem)
1284 		{
1285 			mechItem->setSelectionMode(MechanicsItem::sm_move);
1286 			mechItem->setParentItem(nullptr);
1287 		}
1288 	} else if ( !p_selectList->contains(mechItem) )
1289 	{
1290 		if (!eventInfo.ctrlPressed)
1291 			p_mechanicsDocument->unselectAll();
1292 
1293 		p_mechanicsDocument->select(item);
1294 
1295 		if (mechItem)
1296 			mechItem->setSelectionMode(MechanicsItem::sm_move);
1297 	} else {
1298 		if (mechItem)
1299 			mechItem->setSelectionMode(MechanicsItem::sm_move);
1300 
1301 		if (m_eventInfo.ctrlPressed)
1302 			p_mechanicsDocument->unselect(item);
1303 	}
1304 
1305 	if ( p_selectList->isEmpty() )
1306 		return true;
1307 
1308 	p_mechItemSelectList->setSelectionMode( MechanicsItem::sm_move );
1309 	p_mechItemSelectList->setRaised(true);
1310 	return false;
1311 }
1312 
1313 
mouseMoved(const EventInfo & eventInfo)1314 bool CMMechItemMove::mouseMoved( const EventInfo &eventInfo )
1315 {
1316 	const QPoint pos = eventInfo.pos;
1317 
1318 	int x = pos.x();
1319 	int y = pos.y();
1320 
1321 	const MechItemList itemList = p_mechItemSelectList->toplevelMechItemList();
1322 	const MechItemList::const_iterator ilEnd = itemList.end();
1323 	for ( MechItemList::const_iterator it = itemList.begin(); it != ilEnd; ++it )
1324 	{
1325 		if (*it)
1326 			(*it)->moveBy( x - m_prevPos.x(), y - m_prevPos.y() );
1327 	}
1328 
1329 	m_prevPos = QPoint( x, y );
1330 
1331 	p_canvas->update();
1332 	p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems );
1333 	return false;
1334 }
1335 
1336 
mouseReleased(const EventInfo & eventInfo)1337 bool CMMechItemMove::mouseReleased( const EventInfo &eventInfo )
1338 {
1339 	const QPoint pos = eventInfo.pos;
1340 
1341 	int dx = pos.x() - m_eventInfo.pos.x();
1342 	int dy = pos.y() - m_eventInfo.pos.y();
1343 
1344 	p_mechItemSelectList->setRaised(false);
1345 
1346 	MechanicsItem *mechItem = dynamic_cast<MechanicsItem*>(m_eventInfo.qcanvasItemClickedOn);
1347 	if ( dx == 0 && dy == 0 )
1348 	{
1349 		if ( mechItem && mechItem->isSelected() )
1350 		{
1351 			if ( m_prevClickedOnSM == MechanicsItem::sm_resize )
1352 				mechItem->setSelectionMode( MechanicsItem::sm_rotate );
1353 			else
1354 				mechItem->setSelectionMode( MechanicsItem::sm_resize );
1355 		}
1356 		p_itemDocument->requestStateSave();
1357 		return true;
1358 	}
1359 
1360 	if ( mechItem && mechItem->isSelected() )
1361 	{
1362 		if ( m_prevClickedOnSM == MechanicsItem::sm_rotate )
1363 			mechItem->setSelectionMode(MechanicsItem::sm_rotate);
1364 		else
1365 			mechItem->setSelectionMode(MechanicsItem::sm_resize);
1366 	}
1367 
1368 	QStringList itemIDs;
1369 
1370 	ItemList itemList = p_mechItemSelectList->items();
1371 	const ItemList::iterator ilEnd = itemList.end();
1372 	for ( ItemList::iterator it = itemList.begin(); it != ilEnd; ++it )
1373 	{
1374 		if (*it) {
1375 			itemIDs.append( (*it)->id() );
1376 		}
1377 	}
1378 
1379 	p_mechItemSelectList->setSelectionMode( MechanicsItem::sm_resize );
1380 	p_itemDocument->requestStateSave();
1381 	p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems );
1382 	return true;
1383 }
1384 
1385 
1386 
1387 //BEGIN class SelectRectangle
SelectRectangle(int x,int y,int w,int h,KtlQCanvas * qcanvas)1388 SelectRectangle::SelectRectangle( int x, int y, int w, int h, KtlQCanvas *qcanvas )
1389 	: m_x(x), m_y(y)
1390 {
1391 	m_topLine = new KtlQCanvasLine(qcanvas);
1392 	m_rightLine = new KtlQCanvasLine(qcanvas);
1393 	m_bottomLine = new KtlQCanvasLine(qcanvas);
1394 	m_leftLine = new KtlQCanvasLine(qcanvas);
1395 	setSize( w, h );
1396 
1397 	KtlQCanvasLine* lines[] = { m_topLine, m_rightLine, m_bottomLine, m_leftLine };
1398 	for ( int i=0; i<4; ++ i)
1399 	{
1400 		lines[i]->setPen( QPen( QColor(190,190,190), 1, Qt::DotLine ) );
1401 		lines[i]->setZ( ICNDocument::Z::Select );
1402 		lines[i]->show();
1403 	}
1404 }
1405 
1406 
~SelectRectangle()1407 SelectRectangle::~SelectRectangle()
1408 {
1409 	delete m_topLine;
1410 	delete m_rightLine;
1411 	delete m_bottomLine;
1412 	delete m_leftLine;
1413 }
1414 
1415 
setSize(int w,int h)1416 void SelectRectangle::setSize( int w, int h )
1417 {
1418 	m_topLine->setPoints( m_x, m_y, m_x+w, m_y );
1419 	m_rightLine->setPoints( m_x+w, m_y, m_x+w, m_y+h );
1420 	m_bottomLine->setPoints( m_x+w, m_y+h, m_x, m_y+h );
1421 	m_leftLine->setPoints( m_x, m_y+h, m_x, m_y );
1422 	m_w = w;
1423 	m_h = h;
1424 }
1425 
1426 
collisions()1427 KtlQCanvasItemList SelectRectangle::collisions()
1428 {
1429 	KtlQCanvas *canvas = m_topLine->canvas();
1430 
1431 	return canvas->collisions( QRect( m_x, m_y, m_w, m_h ) );
1432 }
1433 //END class SelectRectangle
1434 
1435 
1436 //BEGIN class CMSelect
CMSelect(ItemDocument * itemDocument,CMManager * cmManager)1437 CMSelect::CMSelect( ItemDocument *itemDocument, CMManager *cmManager )
1438 	: CanvasManipulator( itemDocument, cmManager )
1439 {
1440 	m_selectRectangle = nullptr;
1441 }
1442 
~CMSelect()1443 CMSelect::~CMSelect()
1444 {
1445 	delete m_selectRectangle;
1446 }
1447 
construct(ItemDocument * itemDocument,CMManager * cmManager)1448 CanvasManipulator* CMSelect::construct( ItemDocument *itemDocument, CMManager *cmManager )
1449 {
1450 	return new CMSelect(itemDocument,cmManager);
1451 }
1452 
manipulatorInfo()1453 ManipulatorInfo *CMSelect::manipulatorInfo()
1454 {
1455 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
1456 // 	eventInfo->m_itemType.m_activate = CMManager::it_none;
1457 	eventInfo->m_acceptManipulationPtr = CMSelect::acceptManipulation;
1458 	eventInfo->m_createManipulatorPtr = CMSelect::construct;
1459 	return eventInfo;
1460 }
1461 
acceptManipulation(uint,uint,uint itemType,uint)1462 bool CMSelect::acceptManipulation( uint /*eventState*/, uint /*cmState*/, uint itemType, uint /*cnItemType*/ )
1463 {
1464 	return (itemType & CMManager::it_none);
1465 }
1466 
1467 
mousePressedInitial(const EventInfo & eventInfo)1468 bool CMSelect::mousePressedInitial( const EventInfo &eventInfo )
1469 {
1470 	m_eventInfo = eventInfo;
1471 
1472     if (!eventInfo.ctrlPressed) {
1473 		p_itemDocument->unselectAll();
1474 	}
1475 
1476 	m_selectRectangle = new SelectRectangle( eventInfo.pos.x(), eventInfo.pos.y(), 0, 0, p_canvas );
1477 	return false;
1478 }
1479 
1480 
mouseMoved(const EventInfo & eventInfo)1481 bool CMSelect::mouseMoved( const EventInfo &eventInfo )
1482 {
1483 	QPoint pos = eventInfo.pos;
1484 
1485     m_selectRectangle->setSize( pos.x()-m_eventInfo.pos.x(), pos.y()-m_eventInfo.pos.y() );
1486 
1487 	if (m_eventInfo.ctrlPressed) {
1488 		p_itemDocument->select( m_selectRectangle->collisions() );
1489 	} else if (p_selectList) {
1490 		p_selectList->setItems( m_selectRectangle->collisions() );
1491 	}
1492 
1493 	if (p_selectList && !p_mechanicsDocument) {
1494 		p_selectList->setSelected(true);
1495 	}
1496 	return false;
1497 }
1498 
1499 
mouseReleased(const EventInfo &)1500 bool CMSelect::mouseReleased( const EventInfo &/*eventInfo*/ )
1501 {
1502 	delete m_selectRectangle;
1503 	m_selectRectangle = nullptr;
1504 
1505 	return true;
1506 }
1507 //END class CMSelect
1508 
1509 
CMItemDrag(ItemDocument * itemDocument,CMManager * cmManager)1510 CMItemDrag::CMItemDrag( ItemDocument *itemDocument, CMManager *cmManager )
1511 	: CanvasManipulator( itemDocument, cmManager )
1512 {
1513 	b_dragged = false;
1514 }
1515 
~CMItemDrag()1516 CMItemDrag::~CMItemDrag()
1517 {
1518 }
1519 
construct(ItemDocument * itemDocument,CMManager * cmManager)1520 CanvasManipulator* CMItemDrag::construct( ItemDocument *itemDocument, CMManager *cmManager )
1521 {
1522 	return new CMItemDrag(itemDocument,cmManager);
1523 }
1524 
manipulatorInfo()1525 ManipulatorInfo *CMItemDrag::manipulatorInfo()
1526 {
1527 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
1528 // 	eventInfo->m_itemType.m_activate = CMManager::it_canvas_item;
1529 	eventInfo->m_acceptManipulationPtr = CMItemDrag::acceptManipulation;
1530 	eventInfo->m_createManipulatorPtr = CMItemDrag::construct;
1531 	return eventInfo;
1532 }
1533 
acceptManipulation(uint,uint,uint itemType,uint cnItemType)1534 bool CMItemDrag::acceptManipulation( uint /*eventState*/, uint /*cmState*/, uint itemType, uint cnItemType )
1535 {
1536 	return (itemType & (CMManager::it_canvas_item|CMManager::it_pin)) && !(cnItemType & CMManager::isi_isMovable);
1537 }
1538 
1539 
mousePressedInitial(const EventInfo & eventInfo)1540 bool CMItemDrag::mousePressedInitial( const EventInfo &eventInfo )
1541 {
1542 	m_eventInfo = eventInfo;
1543 	b_dragged = false;
1544 	return false;
1545 }
1546 
1547 
mouseMoved(const EventInfo & eventInfo)1548 bool CMItemDrag::mouseMoved( const EventInfo &eventInfo )
1549 {
1550 	const QPoint pos = eventInfo.pos;
1551 
1552 	if ( b_dragged ||
1553 		 pos.x() > (m_eventInfo.pos.x()+4 ) ||
1554 		 pos.x() < (m_eventInfo.pos.x()-4) ||
1555 		 pos.y() > (m_eventInfo.pos.y()+4) ||
1556 		 pos.y() < (m_eventInfo.pos.y()-4) )
1557 	{
1558 
1559 		b_dragged = true;
1560 
1561 		if ( PinItem * pi = dynamic_cast<PinItem*>(m_eventInfo.qcanvasItemClickedOn) )
1562 			pi->dragged( pos.x() - m_eventInfo.pos.x() );
1563 	}
1564 	return false;
1565 }
1566 
1567 
mouseReleased(const EventInfo &)1568 bool CMItemDrag::mouseReleased( const EventInfo &/*eventInfo*/ )
1569 {
1570 	if ( !b_dragged )
1571 	{
1572 		if ( PinItem * pi = dynamic_cast<PinItem*>(m_eventInfo.qcanvasItemClickedOn) )
1573 			pi->switchState();
1574 	}
1575 
1576 	p_itemDocument->requestStateSave();
1577 	return true;
1578 }
1579 
1580 
1581 //BEGIN class CanvasEllipseDraw
CanvasEllipseDraw(int x,int y,KtlQCanvas * canvas)1582 CanvasEllipseDraw::CanvasEllipseDraw( int x, int y, KtlQCanvas * canvas )
1583 	: KtlQCanvasEllipse( 0, 0, canvas )
1584 {
1585 	move( x, y );
1586 }
1587 
drawShape(QPainter & p)1588 void CanvasEllipseDraw::drawShape( QPainter & p )
1589 {
1590 	p.drawEllipse( int(x()-width()/2), int(y()-height()/2), width(), height() );
1591 }
1592 //END class CanvasEllipseDraw
1593 
1594 
1595 //BEGIN class CMDraw
CMDraw(ItemDocument * itemDocument,CMManager * cmManager)1596 CMDraw::CMDraw( ItemDocument *itemDocument, CMManager *cmManager )
1597 	: CanvasManipulator( itemDocument, cmManager )
1598 {
1599 	m_pDrawLine = nullptr;
1600 	m_pDrawRectangle = nullptr;
1601 	m_pDrawEllipse = nullptr;
1602 }
1603 
~CMDraw()1604 CMDraw::~CMDraw()
1605 {
1606 	p_cmManager->setDrawAction(-1);
1607 }
1608 
construct(ItemDocument * itemDocument,CMManager * cmManager)1609 CanvasManipulator* CMDraw::construct( ItemDocument *itemDocument, CMManager *cmManager )
1610 {
1611 	return new CMDraw(itemDocument,cmManager);
1612 }
1613 
manipulatorInfo()1614 ManipulatorInfo *CMDraw::manipulatorInfo()
1615 {
1616 	ManipulatorInfo *eventInfo = new ManipulatorInfo();
1617 	eventInfo->m_acceptManipulationPtr = CMDraw::acceptManipulation;
1618 	eventInfo->m_createManipulatorPtr = CMDraw::construct;
1619 	return eventInfo;
1620 }
1621 
acceptManipulation(uint,uint cmState,uint,uint)1622 bool CMDraw::acceptManipulation( uint /*eventState*/, uint cmState, uint /*itemType*/, uint /*cnItemType*/ )
1623 {
1624 	return (cmState & CMManager::cms_draw);
1625 }
1626 
mousePressedInitial(const EventInfo & eventInfo)1627 bool CMDraw::mousePressedInitial( const EventInfo &eventInfo )
1628 {
1629 	m_eventInfo = eventInfo;
1630 
1631 	switch ( (DrawPart::DrawAction) p_cmManager->drawAction() )
1632 	{
1633 		case DrawPart::da_text:
1634 		case DrawPart::da_rectangle:
1635 		case DrawPart::da_image:
1636 		{
1637 			m_pDrawRectangle = new KtlQCanvasRectangle( eventInfo.pos.x(), eventInfo.pos.y(), 0, 0, p_canvas );
1638 			m_pDrawRectangle->setPen( QPen( QColor(0,0,0), 1 ) );
1639 			m_pDrawRectangle->setZ( ICNDocument::Z::ConnectorCreateLine );
1640 			m_pDrawRectangle->show();
1641 			break;
1642 		}
1643 		case DrawPart::da_ellipse:
1644 		{
1645 			m_pDrawEllipse = new CanvasEllipseDraw( eventInfo.pos.x(), eventInfo.pos.y(), p_canvas );
1646 			m_pDrawEllipse->setPen( QPen( QColor(0,0,0), 1 ) );
1647 			m_pDrawEllipse->setZ( ICNDocument::Z::ConnectorCreateLine );
1648 			m_pDrawEllipse->show();
1649 			break;
1650 		}
1651 		case DrawPart::da_line:
1652 		case DrawPart::da_arrow:
1653 		{
1654 			m_pDrawLine = new KtlQCanvasLine(p_canvas);
1655 			m_pDrawLine->setPoints( eventInfo.pos.x(), eventInfo.pos.y(), eventInfo.pos.x(), eventInfo.pos.y() );
1656 			m_pDrawLine->setPen( QPen( QColor(0,0,0), 1 ) );
1657 			m_pDrawLine->setZ( ICNDocument::Z::ConnectorCreateLine );
1658 			m_pDrawLine->show();
1659 			break;
1660 		}
1661 		default:
1662 			return true;
1663 	}
1664 
1665 	return false;
1666 }
1667 
1668 
mouseMoved(const EventInfo & eventInfo)1669 bool CMDraw::mouseMoved( const EventInfo &eventInfo )
1670 {
1671 	const QPoint pos = eventInfo.pos;
1672 
1673 	if (m_pDrawRectangle)
1674 		m_pDrawRectangle->setSize( pos.x()-m_eventInfo.pos.x(), pos.y()-m_eventInfo.pos.y() );
1675 
1676 	else if (m_pDrawEllipse) {
1677 // 		QRect r( m_eventInfo.pos.x(), m_eventInfo.pos.y(), pos.x()-m_eventInfo.pos.x(), pos.y()-m_eventInfo.pos.y() );
1678 // 		r = r.normalized();
1679 //
1680 // 		m_pDrawEllipse->setSize( r.width(), r.height() );
1681 // 		m_pDrawEllipse->move( r.left()+(r.width()/2), r.top()+(r.height()/2) );
1682 
1683 		m_pDrawEllipse->setSize( 2 * abs(pos.x() - m_eventInfo.pos.x()), 2 * abs(pos.y() - m_eventInfo.pos.y()) );
1684 	}
1685 
1686 	else if (m_pDrawLine)
1687 		m_pDrawLine->setPoints( eventInfo.pos.x(), eventInfo.pos.y(), m_pDrawLine->endPoint().x(), m_pDrawLine->endPoint().y() );
1688 	else return true;
1689 
1690 	return false;
1691 }
1692 
1693 
mouseReleased(const EventInfo &)1694 bool CMDraw::mouseReleased( const EventInfo & /*eventInfo*/ )
1695 {
1696 	//const QPoint pos = eventInfo.pos; // 2017.10.01 - comment out unused variable
1697 
1698 	QRect sizeRect;
1699 
1700 	if ( m_pDrawRectangle || m_pDrawEllipse )
1701 	{
1702 		if (m_pDrawRectangle)
1703 		{
1704 			sizeRect = m_pDrawRectangle->rect();
1705 
1706 			// We have to manually adjust the size rect so that it matches up with what the user has drawn
1707 
1708 			sizeRect.setWidth( sizeRect.width()+1 );
1709 			sizeRect.setHeight( sizeRect.height()+1 );
1710 
1711 			sizeRect = sizeRect.normalized();
1712 
1713 			if ( m_pDrawRectangle->rect().width() < 0 )
1714 				sizeRect.moveLeft( sizeRect.left() + 1);
1715 
1716 			if ( m_pDrawRectangle->rect().height() < 0 )
1717 				sizeRect.moveTop( sizeRect.top() + 1);
1718 		} else {
1719 			int w = m_pDrawEllipse->width()+1;
1720 			int h = m_pDrawEllipse->height()+1;
1721 			int x = int(m_pDrawEllipse->x()-w/2);
1722 			int y = int(m_pDrawEllipse->y()-h/2);
1723 			sizeRect = QRect( x, y, w, h ).normalized();
1724 		}
1725 
1726 		delete m_pDrawRectangle;
1727 		delete m_pDrawEllipse;
1728 		m_pDrawRectangle = nullptr;
1729 		m_pDrawEllipse = nullptr;
1730 	} else if (m_pDrawLine) {
1731 		int sx = m_pDrawLine->startPoint().x();
1732 		int sy = m_pDrawLine->startPoint().y();
1733 		int ex = m_pDrawLine->endPoint().x();
1734 		int ey = m_pDrawLine->endPoint().y();
1735 
1736 		sizeRect = QRect( ex, ey, sx-ex, sy-ey );
1737 
1738 		delete m_pDrawLine;
1739 		m_pDrawLine = nullptr;
1740 	} else return true;
1741 
1742 	QString id;
1743 	switch ( (DrawPart::DrawAction) p_cmManager->drawAction() )
1744 	{
1745 		case DrawPart::da_rectangle:
1746 			id = "dp/rectangle";
1747 			break;
1748 
1749 		case DrawPart::da_image:
1750 			id = "dp/image";
1751 			break;
1752 
1753 		case DrawPart::da_ellipse:
1754 			id = "dp/ellipse";
1755 			break;
1756 
1757 		case DrawPart::da_text:
1758 			id = "dp/canvas_text";
1759 
1760 			if ( sizeRect.width() < 56 )
1761 				sizeRect.setWidth( 56 );
1762 
1763 			if ( sizeRect.height() < 24 )
1764 				sizeRect.setHeight( 24 );
1765 
1766 			break;
1767 
1768 		case DrawPart::da_line:
1769 			id = "dp/line";
1770 			break;
1771 
1772 		case DrawPart::da_arrow:
1773 			id = "dp/arrow";
1774 			break;
1775 	}
1776 
1777 	if ( id.isEmpty() ) return true;
1778 
1779 	Item *item = p_itemDocument->addItem( id, sizeRect.topLeft(), true );
1780 
1781 	if (!item) return true;
1782 
1783 	item->move( sizeRect.x(), sizeRect.y() ); // We call this again as p_itemDocument->addItem will move the item if it is slightly off the canvas.
1784 
1785 	item->setSize( 0, 0, sizeRect.width(), sizeRect.height() );
1786 
1787 	p_itemDocument->requestStateSave();
1788 	return true;
1789 }
1790 //END class CMDraw
1791 
1792 
1793 //BEGIN class ManualConnectorDraw
ManualConnectorDraw(ICNDocument * _icnDocument,const QPoint & initialPos)1794 ManualConnectorDraw::ManualConnectorDraw( ICNDocument *_icnDocument, const QPoint &initialPos )
1795 {
1796 	m_color = Qt::black;
1797 
1798 	icnDocument = _icnDocument;
1799 	m_currentPos = m_previousPos = m_initialPos = initialPos;
1800 	p_initialItem = icnDocument->itemAtTop(initialPos);
1801 
1802 	b_currentVertical = false;
1803 	b_orientationDefined = false;
1804 
1805 	m_connectorLines.append( m_previousCon = new KtlQCanvasLine( icnDocument->canvas() ) );
1806 	m_connectorLines.append( m_currentCon = new KtlQCanvasLine( icnDocument->canvas() ) );
1807 
1808 	m_currentCon->setPoints( initialPos.x(), initialPos.y(), initialPos.x(), initialPos.y() );
1809 	m_previousCon->setPoints( initialPos.x(), initialPos.y(), initialPos.x(), initialPos.y() );
1810 
1811 	m_currentCon->setPen( m_color );
1812 	m_previousCon->setPen( m_color );
1813 
1814 	updateConnectorEnds();
1815 
1816 	m_currentCon->show();
1817 	m_previousCon->show();
1818 }
1819 
1820 
~ManualConnectorDraw()1821 ManualConnectorDraw::~ManualConnectorDraw()
1822 {
1823 	const QList<KtlQCanvasLine*>::iterator end = m_connectorLines.end();
1824 	for ( QList<KtlQCanvasLine*>::iterator it = m_connectorLines.begin(); it != end; ++it )
1825 		delete *it;
1826 
1827 	m_connectorLines.clear();
1828 }
1829 
setColor(const QColor & color)1830 void ManualConnectorDraw::setColor( const QColor & color )
1831 {
1832 	m_color = color;
1833 
1834 	const QList<KtlQCanvasLine*>::iterator end = m_connectorLines.end();
1835 	for ( QList<KtlQCanvasLine*>::iterator it = m_connectorLines.begin(); it != end; ++it )
1836 		(*it)->setPen( m_color );
1837 }
1838 
mouseMoved(const QPoint & pos)1839 void ManualConnectorDraw::mouseMoved( const QPoint &pos )
1840 {
1841 	if ( m_currentPos == pos ) return;
1842 
1843 	if (!b_orientationDefined)
1844 	{
1845 		QPoint previousStart = m_previousCon->startPoint();
1846 
1847 		double distance = std::sqrt( std::pow( (double)(m_currentPos.x()-previousStart.x()), 2. ) +
1848 									 std::pow( (double)(m_currentPos.y()-previousStart.y()), 2. ) );
1849 
1850 		if ( distance < 24 )
1851 		{
1852 			b_currentVertical = ( std::abs( double(m_currentPos.x()-previousStart.x()) ) >= std::abs( double(m_currentPos.y()-previousStart.y()) ) );
1853 		}
1854 
1855 	}
1856 
1857 	m_previousPos = m_currentPos;
1858 	m_currentPos = pos;
1859 	updateConnectorEnds();
1860 }
1861 
1862 
mouseClicked(const QPoint & pos)1863 KtlQCanvasItem* ManualConnectorDraw::mouseClicked( const QPoint &pos )
1864 {
1865 	if (b_orientationDefined)
1866 		b_currentVertical = !b_currentVertical;
1867 	else	mouseMoved(pos);
1868 
1869 	b_orientationDefined = true;
1870 
1871 	m_currentPos = pos;
1872 
1873 	KtlQCanvasItem * qcanvasItem = icnDocument->itemAtTop(pos);
1874 
1875 	if ( qcanvasItem && pos != m_initialPos && qcanvasItem != p_initialItem )
1876 		return qcanvasItem;
1877 
1878 	m_previousCon = m_currentCon;
1879 
1880 	m_connectorLines.append( m_currentCon = new KtlQCanvasLine( icnDocument->canvas() ) );
1881 	m_currentCon->setPoints( pos.x(), pos.y(), pos.x(), pos.y() );
1882 	m_currentCon->setPen( m_color );
1883 	updateConnectorEnds();
1884 	m_currentCon->show();
1885 
1886 	return nullptr;
1887 }
1888 
1889 
updateConnectorEnds()1890 void ManualConnectorDraw::updateConnectorEnds()
1891 {
1892 	QPoint pivot = m_currentPos;
1893 	QPoint previousStart = m_previousCon->startPoint();
1894 
1895 	if (b_currentVertical)
1896 	{
1897 		pivot.setY( previousStart.y() );
1898 		m_currentCon->setPoints( pivot.x(), pivot.y(), pivot.x(), m_currentPos.y() );
1899 	} else {
1900 		pivot.setX( previousStart.x() );
1901 		m_currentCon->setPoints( pivot.x(), pivot.y(), m_currentPos.x(), pivot.y() );
1902 	}
1903 
1904 	m_previousCon->setPoints( previousStart.x(), previousStart.y(), pivot.x(), pivot.y() );
1905 }
1906 
1907 
pointList()1908 QPointList ManualConnectorDraw::pointList()
1909 {
1910 	QPointList list;
1911 	list.append(m_initialPos);
1912 
1913 	const QList<KtlQCanvasLine*>::iterator end = m_connectorLines.end();
1914 	for ( QList<KtlQCanvasLine*>::iterator it = m_connectorLines.begin(); it != end; ++it )
1915 	{
1916 		list.append( (*it)->endPoint() );
1917 	}
1918 
1919 	return list;
1920 }
1921 //END class ManualConnectorDraw
1922 
1923 
1924 //BEGIN class ManipulatorInfo
ManipulatorInfo()1925 ManipulatorInfo::ManipulatorInfo()
1926 {
1927 }
1928 //END class ManipulatorInfo
1929