1 //////////////////////////////////////////////////////////////////////////
2 //
3 // pgAdmin III - PostgreSQL Tools
4 //
5 // Portions Copyright (C) 1998 - 2011, Julian Smart
6 // Portions Copyright (C) 2011 - 2016, The pgAdmin Development Team
7 // This software is released under the PostgreSQL Licence
8 //
9 // composit.cpp - Composite OGL class
10 //
11 //////////////////////////////////////////////////////////////////////////
12 
13 #include "pgAdmin3.h"
14 
15 #include "ogl/ogl.h"
16 
17 #if wxUSE_PROLOGIO
18 // Sometimes, objects need to access the whole database to
19 // construct themselves.
20 wxExprDatabase *GlobalwxExprDatabase = NULL;
21 #endif
22 
23 /*
24  * Division control point
25  */
26 
27 class wxDivisionControlPoint: public wxControlPoint
28 {
29 	DECLARE_DYNAMIC_CLASS(wxDivisionControlPoint)
30 public:
wxDivisionControlPoint()31 	wxDivisionControlPoint() {}
32 	wxDivisionControlPoint(wxShapeCanvas *the_canvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type);
33 	~wxDivisionControlPoint();
34 
35 	void OnDragLeft(bool draw, double x, double y, int keys = 0, int attachment = 0);
36 	void OnBeginDragLeft(double x, double y, int keys = 0, int attachment = 0);
37 	void OnEndDragLeft(double x, double y, int keys = 0, int attachment = 0);
38 };
39 
IMPLEMENT_DYNAMIC_CLASS(wxDivisionControlPoint,wxControlPoint)40 IMPLEMENT_DYNAMIC_CLASS(wxDivisionControlPoint, wxControlPoint)
41 
42 /*
43  * Composite object
44  *
45  */
46 
47 IMPLEMENT_DYNAMIC_CLASS(wxCompositeShape, wxRectangleShape)
48 
49 wxCompositeShape::wxCompositeShape(): wxRectangleShape(10.0, 10.0)
50 {
51 //  selectable = FALSE;
52 	m_oldX = m_xpos;
53 	m_oldY = m_ypos;
54 }
55 
~wxCompositeShape()56 wxCompositeShape::~wxCompositeShape()
57 {
58 	wxNode *node = m_constraints.GetFirst();
59 	while (node)
60 	{
61 		wxOGLConstraint *constraint = (wxOGLConstraint *)node->GetData();
62 		delete constraint;
63 		node = node->GetNext();
64 	}
65 	node = m_children.GetFirst();
66 	while (node)
67 	{
68 		wxShape *object = (wxShape *)node->GetData();
69 		wxNode *next = node->GetNext();
70 		object->Unlink();
71 		delete object;
72 		node = next;
73 	}
74 }
75 
OnDraw(wxDC & dc)76 void wxCompositeShape::OnDraw(wxDC &dc)
77 {
78 	double x1 = (double)(m_xpos - m_width / 2.0);
79 	double y1 = (double)(m_ypos - m_height / 2.0);
80 
81 	if (m_shadowMode != SHADOW_NONE)
82 	{
83 		if (m_shadowBrush)
84 			dc.SetBrush(* m_shadowBrush);
85 		dc.SetPen(* g_oglTransparentPen);
86 
87 		if (m_cornerRadius != 0.0)
88 			dc.DrawRoundedRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY),
89 			                        WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
90 		else
91 			dc.DrawRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), WXROUND(m_width), WXROUND(m_height));
92 	}
93 }
94 
OnDrawContents(wxDC & dc)95 void wxCompositeShape::OnDrawContents(wxDC &dc)
96 {
97 	wxNode *node = m_children.GetFirst();
98 	while (node)
99 	{
100 		wxShape *object = (wxShape *)node->GetData();
101 		object->Draw(dc);
102 		object->DrawLinks(dc);
103 		node = node->GetNext();
104 	}
105 	wxShape::OnDrawContents(dc);
106 }
107 
OnMovePre(double x,double y,double oldx,double oldy,bool display)108 bool wxCompositeShape::OnMovePre(double x, double y, double oldx, double oldy, bool display)
109 {
110 	double diffX = x - oldx;
111 	double diffY = y - oldy;
112 	wxNode *node = m_children.GetFirst();
113 	while (node)
114 	{
115 		wxShape *object = (wxShape *)node->GetData();
116 
117 		object->Move(object->GetX() + diffX, object->GetY() + diffY, display);
118 
119 		node = node->GetNext();
120 	}
121 	return TRUE;
122 }
123 
124 static double objectStartX = 0.0;
125 static double objectStartY = 0.0;
126 
OnDragLeft(bool WXUNUSED (draw),double x,double y,int WXUNUSED (keys),int WXUNUSED (attachment))127 void wxCompositeShape::OnDragLeft(bool WXUNUSED(draw), double x, double y, int WXUNUSED(keys), int WXUNUSED(attachment))
128 {
129 	double xx = x;
130 	double yy = y;
131 	m_canvas->Snap(&xx, &yy);
132 	double offsetX = xx - objectStartX;
133 	double offsetY = yy - objectStartY;
134 
135 	wxClientDC dc(GetCanvas());
136 	GetCanvas()->PrepareDC(dc);
137 
138 	dc.SetLogicalFunction(OGLRBLF);
139 	wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
140 	dc.SetPen(dottedPen);
141 	dc.SetBrush((* wxTRANSPARENT_BRUSH));
142 
143 	GetEventHandler()->OnDrawOutline(dc, GetX() + offsetX, GetY() + offsetY, GetWidth(), GetHeight());
144 //  wxShape::OnDragLeft(draw, x, y, keys, attachment);
145 }
146 
OnBeginDragLeft(double x,double y,int WXUNUSED (keys),int WXUNUSED (attachment))147 void wxCompositeShape::OnBeginDragLeft(double x, double y, int WXUNUSED(keys), int WXUNUSED(attachment))
148 {
149 	objectStartX = x;
150 	objectStartY = y;
151 
152 	wxClientDC dc(GetCanvas());
153 	GetCanvas()->PrepareDC(dc);
154 
155 	Erase();
156 
157 	dc.SetLogicalFunction(OGLRBLF);
158 
159 	wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
160 	dc.SetPen(dottedPen);
161 	dc.SetBrush((* wxTRANSPARENT_BRUSH));
162 	m_canvas->CaptureMouse();
163 
164 	double xx = x;
165 	double yy = y;
166 	m_canvas->Snap(&xx, &yy);
167 	double offsetX = xx - objectStartX;
168 	double offsetY = yy - objectStartY;
169 
170 	GetEventHandler()->OnDrawOutline(dc, GetX() + offsetX, GetY() + offsetY, GetWidth(), GetHeight());
171 
172 //  wxShape::OnBeginDragLeft(x, y, keys, attachment);
173 }
174 
OnEndDragLeft(double x,double y,int keys,int WXUNUSED (attachment))175 void wxCompositeShape::OnEndDragLeft(double x, double y, int keys, int WXUNUSED(attachment))
176 {
177 //  wxShape::OnEndDragLeft(x, y, keys, attachment);
178 
179 	wxClientDC dc(GetCanvas());
180 	GetCanvas()->PrepareDC(dc);
181 
182 	m_canvas->ReleaseMouse();
183 
184 	if (!m_draggable)
185 	{
186 		if (m_parent) m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, 0);
187 		return;
188 	}
189 
190 	dc.SetLogicalFunction(wxCOPY);
191 	double xx = x;
192 	double yy = y;
193 	m_canvas->Snap(&xx, &yy);
194 	double offsetX = xx - objectStartX;
195 	double offsetY = yy - objectStartY;
196 
197 	Move(GetX() + offsetX, GetY() + offsetY);
198 
199 	if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
200 }
201 
OnRightClick(double x,double y,int keys,int WXUNUSED (attachment))202 void wxCompositeShape::OnRightClick(double x, double y, int keys, int WXUNUSED(attachment))
203 {
204 	// If we get a ctrl-right click, this means send the message to
205 	// the division, so we can invoke a user interface for dealing with regions.
206 	if (keys & KEY_CTRL)
207 	{
208 		wxNode *node = m_divisions.GetFirst();
209 		while (node)
210 		{
211 			wxDivisionShape *division = (wxDivisionShape *)node->GetData();
212 			wxNode *next = node->GetNext();
213 			int attach = 0;
214 			double dist = 0.0;
215 			if (division->HitTest(x, y, &attach, &dist))
216 			{
217 				division->GetEventHandler()->OnRightClick(x, y, keys, attach);
218 				node = NULL;
219 			}
220 			if (node)
221 				node = next;
222 		}
223 	}
224 }
225 
SetSize(double w,double h,bool recursive)226 void wxCompositeShape::SetSize(double w, double h, bool recursive)
227 {
228 	SetAttachmentSize(w, h);
229 
230 	double xScale = (double)(w / (wxMax(1.0, GetWidth())));
231 	double yScale = (double)(h / (wxMax(1.0, GetHeight())));
232 
233 	m_width = w;
234 	m_height = h;
235 
236 	if (!recursive) return;
237 
238 	wxNode *node = m_children.GetFirst();
239 
240 	wxClientDC dc(GetCanvas());
241 	GetCanvas()->PrepareDC(dc);
242 
243 	double xBound, yBound;
244 	while (node)
245 	{
246 		wxShape *object = (wxShape *)node->GetData();
247 
248 		// Scale the position first
249 		double newX = (double)(((object->GetX() - GetX()) * xScale) + GetX());
250 		double newY = (double)(((object->GetY() - GetY()) * yScale) + GetY());
251 		object->Show(FALSE);
252 		object->Move(newX, newY);
253 		object->Show(TRUE);
254 
255 		// Now set the scaled size
256 		object->GetBoundingBoxMin(&xBound, &yBound);
257 		object->SetSize(object->GetFixedWidth() ? xBound : xScale * xBound,
258 		                object->GetFixedHeight() ? yBound : yScale * yBound);
259 
260 		node = node->GetNext();
261 	}
262 	SetDefaultRegionSize();
263 }
264 
AddChild(wxShape * child,wxShape * addAfter)265 void wxCompositeShape::AddChild(wxShape *child, wxShape *addAfter)
266 {
267 	m_children.Append(child);
268 	child->SetParent(this);
269 	if (m_canvas)
270 	{
271 		// Ensure we add at the right position
272 		if (addAfter)
273 			child->RemoveFromCanvas(m_canvas);
274 		child->AddToCanvas(m_canvas, addAfter);
275 	}
276 }
277 
RemoveChild(wxShape * child)278 void wxCompositeShape::RemoveChild(wxShape *child)
279 {
280 	m_children.DeleteObject(child);
281 	m_divisions.DeleteObject(child);
282 	RemoveChildFromConstraints(child);
283 	child->SetParent(NULL);
284 }
285 
DeleteConstraintsInvolvingChild(wxShape * child)286 void wxCompositeShape::DeleteConstraintsInvolvingChild(wxShape *child)
287 {
288 	wxNode *node = m_constraints.GetFirst();
289 	while (node)
290 	{
291 		wxOGLConstraint *constraint = (wxOGLConstraint *)node->GetData();
292 		wxNode *nextNode = node->GetNext();
293 
294 		if ((constraint->m_constrainingObject == child) ||
295 		        constraint->m_constrainedObjects.Member(child))
296 		{
297 			delete constraint;
298 			delete node;
299 		}
300 		node = nextNode;
301 	}
302 }
303 
RemoveChildFromConstraints(wxShape * child)304 void wxCompositeShape::RemoveChildFromConstraints(wxShape *child)
305 {
306 	wxNode *node = m_constraints.GetFirst();
307 	while (node)
308 	{
309 		wxOGLConstraint *constraint = (wxOGLConstraint *)node->GetData();
310 		wxNode *nextNode = node->GetNext();
311 
312 		if (constraint->m_constrainedObjects.Member(child))
313 			constraint->m_constrainedObjects.DeleteObject(child);
314 		if (constraint->m_constrainingObject == child)
315 			constraint->m_constrainingObject = NULL;
316 
317 		// Delete the constraint if no participants left
318 		if (!constraint->m_constrainingObject)
319 		{
320 			delete constraint;
321 			delete node;
322 		}
323 
324 		node = nextNode;
325 	}
326 }
327 
Copy(wxShape & copy)328 void wxCompositeShape::Copy(wxShape &copy)
329 {
330 	wxRectangleShape::Copy(copy);
331 
332 	wxASSERT( copy.IsKindOf(CLASSINFO(wxCompositeShape)) ) ;
333 
334 	wxCompositeShape &compositeCopy = (wxCompositeShape &) copy;
335 
336 	// Associate old and new copies for compositeCopying constraints and division geometry
337 	oglObjectCopyMapping.Append((long)this, &compositeCopy);
338 
339 	// Copy the children
340 	wxNode *node = m_children.GetFirst();
341 	while (node)
342 	{
343 		wxShape *object = (wxShape *)node->GetData();
344 		wxShape *newObject = object->CreateNewCopy(FALSE, FALSE);
345 		if (newObject->GetId() == 0)
346 			newObject->SetId(wxNewId());
347 
348 		newObject->SetParent(&compositeCopy);
349 		compositeCopy.m_children.Append(newObject);
350 
351 		// Some m_children may be divisions
352 		if (m_divisions.Member(object))
353 			compositeCopy.m_divisions.Append(newObject);
354 
355 		oglObjectCopyMapping.Append((long)object, newObject);
356 
357 		node = node->GetNext();
358 	}
359 
360 	// Copy the constraints
361 	node = m_constraints.GetFirst();
362 	while (node)
363 	{
364 		wxOGLConstraint *constraint = (wxOGLConstraint *)node->GetData();
365 
366 		wxShape *newConstraining = (wxShape *)(oglObjectCopyMapping.Find((long)constraint->m_constrainingObject)->GetData());
367 
368 		wxList newConstrainedList;
369 		wxNode *node2 = constraint->m_constrainedObjects.GetFirst();
370 		while (node2)
371 		{
372 			wxShape *constrainedObject = (wxShape *)node2->GetData();
373 			wxShape *newConstrained = (wxShape *)(oglObjectCopyMapping.Find((long)constrainedObject)->GetData());
374 			newConstrainedList.Append(newConstrained);
375 			node2 = node2->GetNext();
376 		}
377 
378 		wxOGLConstraint *newConstraint = new wxOGLConstraint(constraint->m_constraintType, newConstraining,
379 		        newConstrainedList);
380 		newConstraint->m_constraintId = constraint->m_constraintId;
381 		if (!constraint->m_constraintName.IsEmpty())
382 		{
383 			newConstraint->m_constraintName = constraint->m_constraintName;
384 		}
385 		newConstraint->SetSpacing(constraint->m_xSpacing, constraint->m_ySpacing);
386 		compositeCopy.m_constraints.Append(newConstraint);
387 
388 		node = node->GetNext();
389 	}
390 
391 	// Now compositeCopy the division geometry
392 	node = m_divisions.GetFirst();
393 	while (node)
394 	{
395 		wxDivisionShape *division = (wxDivisionShape *)node->GetData();
396 		wxNode *node1 = oglObjectCopyMapping.Find((long)division);
397 		wxNode *leftNode = NULL;
398 		wxNode *topNode = NULL;
399 		wxNode *rightNode = NULL;
400 		wxNode *bottomNode = NULL;
401 		if (division->GetLeftSide())
402 			leftNode = oglObjectCopyMapping.Find((long)division->GetLeftSide());
403 		if (division->GetTopSide())
404 			topNode = oglObjectCopyMapping.Find((long)division->GetTopSide());
405 		if (division->GetRightSide())
406 			rightNode = oglObjectCopyMapping.Find((long)division->GetRightSide());
407 		if (division->GetBottomSide())
408 			bottomNode = oglObjectCopyMapping.Find((long)division->GetBottomSide());
409 		if (node1)
410 		{
411 			wxDivisionShape *newDivision = (wxDivisionShape *)node1->GetData();
412 			if (leftNode)
413 				newDivision->SetLeftSide((wxDivisionShape *)leftNode->GetData());
414 			if (topNode)
415 				newDivision->SetTopSide((wxDivisionShape *)topNode->GetData());
416 			if (rightNode)
417 				newDivision->SetRightSide((wxDivisionShape *)rightNode->GetData());
418 			if (bottomNode)
419 				newDivision->SetBottomSide((wxDivisionShape *)bottomNode->GetData());
420 		}
421 		node = node->GetNext();
422 	}
423 }
424 
AddConstraint(wxOGLConstraint * constraint)425 wxOGLConstraint *wxCompositeShape::AddConstraint(wxOGLConstraint *constraint)
426 {
427 	m_constraints.Append(constraint);
428 	if (constraint->m_constraintId == 0)
429 		constraint->m_constraintId = wxNewId();
430 	return constraint;
431 }
432 
AddConstraint(int type,wxShape * constraining,wxList & constrained)433 wxOGLConstraint *wxCompositeShape::AddConstraint(int type, wxShape *constraining, wxList &constrained)
434 {
435 	wxOGLConstraint *constraint = new wxOGLConstraint(type, constraining, constrained);
436 	if (constraint->m_constraintId == 0)
437 		constraint->m_constraintId = wxNewId();
438 	m_constraints.Append(constraint);
439 	return constraint;
440 }
441 
AddConstraint(int type,wxShape * constraining,wxShape * constrained)442 wxOGLConstraint *wxCompositeShape::AddConstraint(int type, wxShape *constraining, wxShape *constrained)
443 {
444 	wxList l;
445 	l.Append(constrained);
446 	wxOGLConstraint *constraint = new wxOGLConstraint(type, constraining, l);
447 	if (constraint->m_constraintId == 0)
448 		constraint->m_constraintId = wxNewId();
449 	m_constraints.Append(constraint);
450 	return constraint;
451 }
452 
FindConstraint(long cId,wxCompositeShape ** actualComposite)453 wxOGLConstraint *wxCompositeShape::FindConstraint(long cId, wxCompositeShape **actualComposite)
454 {
455 	wxNode *node = m_constraints.GetFirst();
456 	while (node)
457 	{
458 		wxOGLConstraint *constraint = (wxOGLConstraint *)node->GetData();
459 		if (constraint->m_constraintId == cId)
460 		{
461 			if (actualComposite)
462 				*actualComposite = this;
463 			return constraint;
464 		}
465 		node = node->GetNext();
466 	}
467 	// If not found, try children.
468 	node = m_children.GetFirst();
469 	while (node)
470 	{
471 		wxShape *child = (wxShape *)node->GetData();
472 		if (child->IsKindOf(CLASSINFO(wxCompositeShape)))
473 		{
474 			wxOGLConstraint *constraint = ((wxCompositeShape *)child)->FindConstraint(cId, actualComposite);
475 			if (constraint)
476 			{
477 				if (actualComposite)
478 					*actualComposite = (wxCompositeShape *)child;
479 				return constraint;
480 			}
481 		}
482 		node = node->GetNext();
483 	}
484 	return NULL;
485 }
486 
DeleteConstraint(wxOGLConstraint * constraint)487 void wxCompositeShape::DeleteConstraint(wxOGLConstraint *constraint)
488 {
489 	m_constraints.DeleteObject(constraint);
490 	delete constraint;
491 }
492 
CalculateSize()493 void wxCompositeShape::CalculateSize()
494 {
495 	double maxX = (double) - 999999.9;
496 	double maxY = (double) - 999999.9;
497 	double minX = (double)  999999.9;
498 	double minY = (double)  999999.9;
499 
500 	double w, h;
501 	wxNode *node = m_children.GetFirst();
502 	while (node)
503 	{
504 		wxShape *object = (wxShape *)node->GetData();
505 
506 		// Recalculate size of composite objects because may not conform
507 		// to size it was set to - depends on the children.
508 		object->CalculateSize();
509 
510 		object->GetBoundingBoxMax(&w, &h);
511 		if ((object->GetX() + (w / 2.0)) > maxX)
512 			maxX = (double)(object->GetX() + (w / 2.0));
513 		if ((object->GetX() - (w / 2.0)) < minX)
514 			minX = (double)(object->GetX() - (w / 2.0));
515 		if ((object->GetY() + (h / 2.0)) > maxY)
516 			maxY = (double)(object->GetY() + (h / 2.0));
517 		if ((object->GetY() - (h / 2.0)) < minY)
518 			minY = (double)(object->GetY() - (h / 2.0));
519 
520 		node = node->GetNext();
521 	}
522 	m_width = maxX - minX;
523 	m_height = maxY - minY;
524 	m_xpos = (double)(m_width / 2.0 + minX);
525 	m_ypos = (double)(m_height / 2.0 + minY);
526 }
527 
Recompute()528 bool wxCompositeShape::Recompute()
529 {
530 	int noIterations = 0;
531 	bool changed = TRUE;
532 	while (changed && (noIterations < 500))
533 	{
534 		changed = Constrain();
535 		noIterations ++;
536 	}
537 	/*
538 	#ifdef wx_x
539 	  if (changed)
540 	    cerr << "Warning: constraint algorithm failed after 500 iterations.\n";
541 	#endif
542 	*/
543 	return (!changed);
544 }
545 
Constrain()546 bool wxCompositeShape::Constrain()
547 {
548 	CalculateSize();
549 
550 	bool changed = FALSE;
551 	wxNode *node = m_children.GetFirst();
552 	while (node)
553 	{
554 		wxShape *object = (wxShape *)node->GetData();
555 		if (object->Constrain())
556 			changed = TRUE;
557 		node = node->GetNext();
558 	}
559 
560 	node = m_constraints.GetFirst();
561 	while (node)
562 	{
563 		wxOGLConstraint *constraint = (wxOGLConstraint *)node->GetData();
564 		if (constraint->Evaluate()) changed = TRUE;
565 		node = node->GetNext();
566 	}
567 	return changed;
568 }
569 
570 #if wxUSE_PROLOGIO
WriteAttributes(wxExpr * clause)571 void wxCompositeShape::WriteAttributes(wxExpr *clause)
572 {
573 	wxRectangleShape::WriteAttributes(clause);
574 
575 //  clause->AddAttributeValue("selectable", (long)selectable);
576 
577 	// Output constraints as constraint1 = (...), constraint2 = (...), etc.
578 	int constraintNo = 1;
579 	wxChar m_constraintNameBuf[20];
580 	wxNode *node = m_constraints.GetFirst();
581 	while (node)
582 	{
583 		wxOGLConstraint *constraint = (wxOGLConstraint *)node->GetData();
584 		wxSprintf(m_constraintNameBuf, wxT("constraint%d"), constraintNo);
585 
586 		// Each constraint is stored in the form
587 		// (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
588 		wxExpr *constraintExpr = new wxExpr(wxExprList);
589 		constraintExpr->Append(new wxExpr((long)constraint->m_constraintType));
590 		constraintExpr->Append(new wxExpr(wxExprString, constraint->m_constraintName));
591 		constraintExpr->Append(new wxExpr(constraint->m_constraintId));
592 		constraintExpr->Append(new wxExpr(constraint->m_xSpacing));
593 		constraintExpr->Append(new wxExpr(constraint->m_ySpacing));
594 		constraintExpr->Append(new wxExpr(constraint->m_constrainingObject->GetId()));
595 
596 		wxExpr *objectList = new wxExpr(wxExprList);
597 		wxNode *node1 = constraint->m_constrainedObjects.GetFirst();
598 		while (node1)
599 		{
600 			wxShape *obj = (wxShape *)node1->GetData();
601 			objectList->Append(new wxExpr(obj->GetId()));
602 			node1 = node1->GetNext();
603 		}
604 		constraintExpr->Append(objectList);
605 
606 		clause->AddAttributeValue(m_constraintNameBuf, constraintExpr);
607 
608 		node = node->GetNext();
609 		constraintNo ++;
610 	}
611 
612 	// Write the ids of all the child images
613 	wxExpr *childrenExpr = new wxExpr(wxExprList);
614 	node = m_children.GetFirst();
615 	while (node)
616 	{
617 		wxShape *child = (wxShape *)node->GetData();
618 		childrenExpr->Append(new wxExpr(child->GetId()));
619 		node = node->GetNext();
620 	}
621 	clause->AddAttributeValue(wxT("children"), childrenExpr);
622 
623 	// Write the ids of all the division images
624 	if (m_divisions.GetCount() > 0)
625 	{
626 		wxExpr *divisionsExpr = new wxExpr(wxExprList);
627 		node = m_divisions.GetFirst();
628 		while (node)
629 		{
630 			wxShape *child = (wxShape *)node->GetData();
631 			divisionsExpr->Append(new wxExpr(child->GetId()));
632 			node = node->GetNext();
633 		}
634 		clause->AddAttributeValue(wxT("divisions"), divisionsExpr);
635 	}
636 }
637 
638 // Problem. Child images are always written AFTER the parent
639 // so as to be able to link up to parent. So we may not be able
640 // to find the constraint participants until we've read everything
641 // in. Need to have another pass for composites.
ReadAttributes(wxExpr * clause)642 void wxCompositeShape::ReadAttributes(wxExpr *clause)
643 {
644 	wxRectangleShape::ReadAttributes(clause);
645 
646 //  clause->GetAttributeValue("selectable", selectable);
647 }
648 
ReadConstraints(wxExpr * clause,wxExprDatabase * database)649 void wxCompositeShape::ReadConstraints(wxExpr *clause, wxExprDatabase *database)
650 {
651 	// Constraints are output as constraint1 = (...), constraint2 = (...), etc.
652 	int constraintNo = 1;
653 	wxChar m_constraintNameBuf[20];
654 	bool haveConstraints = TRUE;
655 
656 	while (haveConstraints)
657 	{
658 		wxSprintf(m_constraintNameBuf, wxT("constraint%d"), constraintNo);
659 		wxExpr *constraintExpr = NULL;
660 		clause->GetAttributeValue(m_constraintNameBuf, &constraintExpr);
661 		if (!constraintExpr)
662 		{
663 			haveConstraints = FALSE;
664 			break;
665 		}
666 		wxString cName = wxEmptyString;
667 		wxShape *m_constrainingObject = NULL;
668 		wxList m_constrainedObjects;
669 
670 		// Each constraint is stored in the form
671 		// (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
672 
673 		wxExpr *typeExpr = constraintExpr->Nth(0);
674 		wxExpr *nameExpr = constraintExpr->Nth(1);
675 		wxExpr *idExpr = constraintExpr->Nth(2);
676 		wxExpr *xExpr = constraintExpr->Nth(3);
677 		wxExpr *yExpr = constraintExpr->Nth(4);
678 		wxExpr *constrainingExpr = constraintExpr->Nth(5);
679 		wxExpr *constrainedExpr = constraintExpr->Nth(6);
680 
681 		int cType = (int)typeExpr->IntegerValue();
682 		double cXSpacing = xExpr->RealValue();
683 		double cYSpacing = yExpr->RealValue();
684 		cName = nameExpr->StringValue();
685 		long cId = idExpr->IntegerValue();
686 
687 		wxExpr *objExpr1 = database->HashFind(wxT("node_image"), constrainingExpr->IntegerValue());
688 		if (objExpr1 && objExpr1->GetClientData())
689 			m_constrainingObject = (wxShape *)objExpr1->GetClientData();
690 		else
691 			wxLogFatalError(wxT("Object graphics error: Couldn't find constraining image of composite."));
692 
693 		int i = 0;
694 		wxExpr *currentIdExpr = constrainedExpr->Nth(i);
695 		while (currentIdExpr)
696 		{
697 			long currentId = currentIdExpr->IntegerValue();
698 			wxExpr *objExpr2 = database->HashFind(wxT("node_image"), currentId);
699 			if (objExpr2 && objExpr2->GetClientData())
700 			{
701 				m_constrainedObjects.Append((wxShape *)objExpr2->GetClientData());
702 			}
703 			else
704 			{
705 				wxLogFatalError(wxT("Object graphics error: Couldn't find constrained image of composite."));
706 			}
707 
708 			i ++;
709 			currentIdExpr = constrainedExpr->Nth(i);
710 		}
711 		wxOGLConstraint *newConstraint = AddConstraint(cType, m_constrainingObject, m_constrainedObjects);
712 		newConstraint->SetSpacing(cXSpacing, cYSpacing);
713 		newConstraint->m_constraintId = cId;
714 		newConstraint->m_constraintName = cName;
715 		constraintNo ++;
716 	}
717 }
718 #endif
719 
720 // Make this composite into a container by creating one wxDivisionShape
MakeContainer()721 void wxCompositeShape::MakeContainer()
722 {
723 	wxDivisionShape *division = OnCreateDivision();
724 	m_divisions.Append(division);
725 	AddChild(division);
726 
727 	division->SetSize(m_width, m_height);
728 
729 	wxClientDC dc(GetCanvas());
730 	GetCanvas()->PrepareDC(dc);
731 
732 	division->Move(GetX(), GetY());
733 	Recompute();
734 	division->Show(TRUE);
735 }
736 
OnCreateDivision()737 wxDivisionShape *wxCompositeShape::OnCreateDivision()
738 {
739 	return new wxDivisionShape;
740 }
741 
FindContainerImage()742 wxShape *wxCompositeShape::FindContainerImage()
743 {
744 	wxNode *node = m_children.GetFirst();
745 	while (node)
746 	{
747 		wxShape *child = (wxShape *)node->GetData();
748 		if (!m_divisions.Member(child))
749 			return child;
750 		node = node->GetNext();
751 	}
752 	return NULL;
753 }
754 
755 // Returns TRUE if division is a descendant of this container
ContainsDivision(wxDivisionShape * division)756 bool wxCompositeShape::ContainsDivision(wxDivisionShape *division)
757 {
758 	if (m_divisions.Member(division))
759 		return TRUE;
760 	wxNode *node = m_children.GetFirst();
761 	while (node)
762 	{
763 		wxShape *child = (wxShape *)node->GetData();
764 		if (child->IsKindOf(CLASSINFO(wxCompositeShape)))
765 		{
766 			bool ans = ((wxCompositeShape *)child)->ContainsDivision(division);
767 			if (ans)
768 				return TRUE;
769 		}
770 		node = node->GetNext();
771 	}
772 	return FALSE;
773 }
774 
775 /*
776  * Division object
777  *
778  */
779 
IMPLEMENT_DYNAMIC_CLASS(wxDivisionShape,wxCompositeShape)780 IMPLEMENT_DYNAMIC_CLASS(wxDivisionShape, wxCompositeShape)
781 
782 wxDivisionShape::wxDivisionShape()
783 {
784 	SetSensitivityFilter(OP_CLICK_LEFT | OP_CLICK_RIGHT | OP_DRAG_RIGHT);
785 	SetCentreResize(FALSE);
786 	SetAttachmentMode(TRUE);
787 	m_leftSide = NULL;
788 	m_rightSide = NULL;
789 	m_topSide = NULL;
790 	m_bottomSide = NULL;
791 	m_handleSide = DIVISION_SIDE_NONE;
792 	m_leftSidePen = (wxPen *) wxBLACK_PEN;
793 	m_topSidePen = (wxPen *) wxBLACK_PEN;
794 	m_leftSideColour = wxT("BLACK");
795 	m_topSideColour = wxT("BLACK");
796 	m_leftSideStyle = wxT("Solid");
797 	m_topSideStyle = wxT("Solid");
798 	ClearRegions();
799 }
800 
~wxDivisionShape()801 wxDivisionShape::~wxDivisionShape()
802 {
803 }
804 
OnDraw(wxDC & dc)805 void wxDivisionShape::OnDraw(wxDC &dc)
806 {
807 	dc.SetBrush(* wxTRANSPARENT_BRUSH);
808 	dc.SetBackgroundMode(wxTRANSPARENT);
809 
810 	double x1 = (double)(GetX() - (GetWidth() / 2.0));
811 	double y1 = (double)(GetY() - (GetHeight() / 2.0));
812 	double x2 = (double)(GetX() + (GetWidth() / 2.0));
813 	double y2 = (double)(GetY() + (GetHeight() / 2.0));
814 
815 	// Should subtract 1 pixel if drawing under Windows
816 #ifdef __WXMSW__
817 	y2 -= (double)1.0;
818 #endif
819 
820 	if (m_leftSide)
821 	{
822 		dc.SetPen(* m_leftSidePen);
823 		dc.DrawLine(WXROUND(x1), WXROUND(y2), WXROUND(x1), WXROUND(y1));
824 	}
825 	if (m_topSide)
826 	{
827 		dc.SetPen(* m_topSidePen);
828 		dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y1));
829 	}
830 
831 	// For testing purposes, draw a rectangle so we know
832 	// how big the division is.
833 //    SetBrush(* wxCYAN_BRUSH);
834 //    wxRectangleShape::OnDraw(dc);
835 }
836 
OnDrawContents(wxDC & dc)837 void wxDivisionShape::OnDrawContents(wxDC &dc)
838 {
839 	wxCompositeShape::OnDrawContents(dc);
840 }
841 
OnMovePre(double x,double y,double oldx,double oldy,bool display)842 bool wxDivisionShape::OnMovePre(double x, double y, double oldx, double oldy, bool display)
843 {
844 	double diffX = x - oldx;
845 	double diffY = y - oldy;
846 	wxNode *node = m_children.GetFirst();
847 	while (node)
848 	{
849 		wxShape *object = (wxShape *)node->GetData();
850 		object->Erase();
851 		object->Move(object->GetX() + diffX, object->GetY() + diffY, display);
852 		node = node->GetNext();
853 	}
854 	return TRUE;
855 }
856 
OnDragLeft(bool draw,double x,double y,int keys,int attachment)857 void wxDivisionShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
858 {
859 	if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
860 	{
861 		attachment = 0;
862 		double dist;
863 		if (m_parent)
864 		{
865 			m_parent->HitTest(x, y, &attachment, &dist);
866 			m_parent->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
867 		}
868 		return;
869 	}
870 	wxShape::OnDragLeft(draw, x, y, keys, attachment);
871 }
872 
OnBeginDragLeft(double x,double y,int keys,int attachment)873 void wxDivisionShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
874 {
875 	if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
876 	{
877 		attachment = 0;
878 		double dist;
879 		if (m_parent)
880 		{
881 			m_parent->HitTest(x, y, &attachment, &dist);
882 			m_parent->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
883 		}
884 		return;
885 	}
886 
887 	wxShape::OnBeginDragLeft(x, y, keys, attachment);
888 }
889 
OnEndDragLeft(double x,double y,int keys,int attachment)890 void wxDivisionShape::OnEndDragLeft(double x, double y, int keys, int attachment)
891 {
892 	m_canvas->ReleaseMouse();
893 	if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
894 	{
895 		attachment = 0;
896 		double dist;
897 		if (m_parent)
898 		{
899 			m_parent->HitTest(x, y, &attachment, &dist);
900 			m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
901 		}
902 		return;
903 	}
904 
905 #if 0
906 	wxClientDC dc(GetCanvas());
907 	GetCanvas()->PrepareDC(dc);
908 
909 	dc.SetLogicalFunction(wxCOPY);
910 #endif
911 
912 	m_canvas->Snap(&m_xpos, &m_ypos);
913 	GetEventHandler()->OnMovePre(x, y, m_oldX, m_oldY);
914 
915 	ResetControlPoints();
916 	MoveLinks();
917 
918 	if (m_canvas)
919 		m_canvas->Refresh();
920 }
921 
SetSize(double w,double h,bool recursive)922 void wxDivisionShape::SetSize(double w, double h, bool recursive)
923 {
924 	m_width = w;
925 	m_height = h;
926 	wxRectangleShape::SetSize(w, h, recursive);
927 }
928 
CalculateSize()929 void wxDivisionShape::CalculateSize()
930 {
931 }
932 
Copy(wxShape & copy)933 void wxDivisionShape::Copy(wxShape &copy)
934 {
935 	wxCompositeShape::Copy(copy);
936 
937 	wxASSERT( copy.IsKindOf(CLASSINFO(wxDivisionShape)) ) ;
938 
939 	wxDivisionShape &divisionCopy = (wxDivisionShape &) copy;
940 
941 	divisionCopy.m_leftSideStyle = m_leftSideStyle;
942 	divisionCopy.m_topSideStyle = m_topSideStyle;
943 	divisionCopy.m_leftSideColour = m_leftSideColour;
944 	divisionCopy.m_topSideColour = m_topSideColour;
945 
946 	divisionCopy.m_leftSidePen = m_leftSidePen;
947 	divisionCopy.m_topSidePen = m_topSidePen;
948 	divisionCopy.m_handleSide = m_handleSide;
949 
950 	// Division geometry copying is handled at the wxCompositeShape level.
951 }
952 
953 #if wxUSE_PROLOGIO
WriteAttributes(wxExpr * clause)954 void wxDivisionShape::WriteAttributes(wxExpr *clause)
955 {
956 	wxCompositeShape::WriteAttributes(clause);
957 
958 	if (m_leftSide)
959 		clause->AddAttributeValue(wxT("left_side"), (long)m_leftSide->GetId());
960 	if (m_topSide)
961 		clause->AddAttributeValue(wxT("top_side"), (long)m_topSide->GetId());
962 	if (m_rightSide)
963 		clause->AddAttributeValue(wxT("right_side"), (long)m_rightSide->GetId());
964 	if (m_bottomSide)
965 		clause->AddAttributeValue(wxT("bottom_side"), (long)m_bottomSide->GetId());
966 
967 	clause->AddAttributeValue(wxT("handle_side"), (long)m_handleSide);
968 	clause->AddAttributeValueString(wxT("left_colour"), m_leftSideColour);
969 	clause->AddAttributeValueString(wxT("top_colour"), m_topSideColour);
970 	clause->AddAttributeValueString(wxT("left_style"), m_leftSideStyle);
971 	clause->AddAttributeValueString(wxT("top_style"), m_topSideStyle);
972 }
973 
ReadAttributes(wxExpr * clause)974 void wxDivisionShape::ReadAttributes(wxExpr *clause)
975 {
976 	wxCompositeShape::ReadAttributes(clause);
977 
978 	clause->GetAttributeValue(wxT("handle_side"), m_handleSide);
979 	clause->GetAttributeValue(wxT("left_colour"), m_leftSideColour);
980 	clause->GetAttributeValue(wxT("top_colour"), m_topSideColour);
981 	clause->GetAttributeValue(wxT("left_style"), m_leftSideStyle);
982 	clause->GetAttributeValue(wxT("top_style"), m_topSideStyle);
983 }
984 #endif
985 
986 // Experimental
OnRightClick(double x,double y,int keys,int attachment)987 void wxDivisionShape::OnRightClick(double x, double y, int keys, int attachment)
988 {
989 	if (keys & KEY_CTRL)
990 	{
991 		PopupMenu(x, y);
992 	}
993 	/*
994 	  else if (keys & KEY_SHIFT)
995 	  {
996 	    if (m_leftSide || m_topSide || m_rightSide || m_bottomSide)
997 	    {
998 	      if (Selected())
999 	      {
1000 	        Select(FALSE);
1001 	        GetParent()->Draw(dc);
1002 	      }
1003 	      else
1004 	        Select(TRUE);
1005 	    }
1006 	  }
1007 	*/
1008 	else
1009 	{
1010 		attachment = 0;
1011 		double dist;
1012 		if (m_parent)
1013 		{
1014 			m_parent->HitTest(x, y, &attachment, &dist);
1015 			m_parent->GetEventHandler()->OnRightClick(x, y, keys, attachment);
1016 		}
1017 		return;
1018 	}
1019 }
1020 
1021 
1022 // Divide wxHORIZONTALly or wxVERTICALly
Divide(int direction)1023 bool wxDivisionShape::Divide(int direction)
1024 {
1025 	// Calculate existing top-left, bottom-right
1026 	double x1 = (double)(GetX() - (GetWidth() / 2.0));
1027 	double y1 = (double)(GetY() - (GetHeight() / 2.0));
1028 	wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent();
1029 	double oldWidth = GetWidth();
1030 	double oldHeight = GetHeight();
1031 	if (Selected())
1032 		Select(FALSE);
1033 
1034 	//wxClientDC dc(GetCanvas());
1035 	//GetCanvas()->PrepareDC(dc);
1036 
1037 	if (direction == wxVERTICAL)
1038 	{
1039 		// Dividing vertically means notionally putting a horizontal line through it.
1040 		// Break existing piece into two.
1041 		double newXPos1 = GetX();
1042 		double newYPos1 = (double)(y1 + (GetHeight() / 4.0));
1043 		double newXPos2 = GetX();
1044 		double newYPos2 = (double)(y1 + (3.0 * GetHeight() / 4.0));
1045 		wxDivisionShape *newDivision = compositeParent->OnCreateDivision();
1046 		newDivision->Show(TRUE);
1047 
1048 		// Erase();
1049 
1050 		// Anything adjoining the bottom of this division now adjoins the
1051 		// bottom of the new division.
1052 		wxNode *node = compositeParent->GetDivisions().GetFirst();
1053 		while (node)
1054 		{
1055 			wxDivisionShape *obj = (wxDivisionShape *)node->GetData();
1056 			if (obj->GetTopSide() == this)
1057 				obj->SetTopSide(newDivision);
1058 			node = node->GetNext();
1059 		}
1060 		newDivision->SetTopSide(this);
1061 		newDivision->SetBottomSide(m_bottomSide);
1062 		newDivision->SetLeftSide(m_leftSide);
1063 		newDivision->SetRightSide(m_rightSide);
1064 		m_bottomSide = newDivision;
1065 
1066 		compositeParent->GetDivisions().Append(newDivision);
1067 
1068 		// CHANGE: Need to insert this division at start of divisions in the object
1069 		// list, because e.g.:
1070 		// 1) Add division
1071 		// 2) Add contained object
1072 		// 3) Add division
1073 		// Division is now receiving mouse events _before_ the contained object,
1074 		// because it was added last (on top of all others)
1075 
1076 		// Add after the image that visualizes the container
1077 		compositeParent->AddChild(newDivision, compositeParent->FindContainerImage());
1078 
1079 		m_handleSide = DIVISION_SIDE_BOTTOM;
1080 		newDivision->SetHandleSide(DIVISION_SIDE_TOP);
1081 
1082 		SetSize(oldWidth, (double)(oldHeight / 2.0));
1083 		Move(newXPos1, newYPos1);
1084 
1085 		newDivision->SetSize(oldWidth, (double)(oldHeight / 2.0));
1086 		newDivision->Move(newXPos2, newYPos2);
1087 	}
1088 	else
1089 	{
1090 		// Dividing horizontally means notionally putting a vertical line through it.
1091 		// Break existing piece into two.
1092 		double newXPos1 = (double)(x1 + (GetWidth() / 4.0));
1093 		double newYPos1 = GetY();
1094 		double newXPos2 = (double)(x1 + (3.0 * GetWidth() / 4.0));
1095 		double newYPos2 = GetY();
1096 		wxDivisionShape *newDivision = compositeParent->OnCreateDivision();
1097 		newDivision->Show(TRUE);
1098 
1099 		// Erase(dc);
1100 
1101 		// Anything adjoining the left of this division now adjoins the
1102 		// left of the new division.
1103 		wxNode *node = compositeParent->GetDivisions().GetFirst();
1104 		while (node)
1105 		{
1106 			wxDivisionShape *obj = (wxDivisionShape *)node->GetData();
1107 			if (obj->GetLeftSide() == this)
1108 				obj->SetLeftSide(newDivision);
1109 			node = node->GetNext();
1110 		}
1111 		newDivision->SetTopSide(m_topSide);
1112 		newDivision->SetBottomSide(m_bottomSide);
1113 		newDivision->SetLeftSide(this);
1114 		newDivision->SetRightSide(m_rightSide);
1115 		m_rightSide = newDivision;
1116 
1117 		compositeParent->GetDivisions().Append(newDivision);
1118 		compositeParent->AddChild(newDivision, compositeParent->FindContainerImage());
1119 
1120 		m_handleSide = DIVISION_SIDE_RIGHT;
1121 		newDivision->SetHandleSide(DIVISION_SIDE_LEFT);
1122 
1123 		SetSize((double)(oldWidth / 2.0), oldHeight);
1124 		Move(newXPos1, newYPos1);
1125 
1126 		newDivision->SetSize((double)(oldWidth / 2.0), oldHeight);
1127 		newDivision->Move(newXPos2, newYPos2);
1128 	}
1129 	if (compositeParent->Selected())
1130 	{
1131 		compositeParent->DeleteControlPoints();
1132 		compositeParent->MakeControlPoints();
1133 		compositeParent->MakeMandatoryControlPoints();
1134 	}
1135 	// compositeParent->Draw(dc);
1136 
1137 	if (GetCanvas())
1138 		GetCanvas()->Refresh();
1139 	return TRUE;
1140 }
1141 
1142 // Make one control point for every visible line
MakeControlPoints()1143 void wxDivisionShape::MakeControlPoints()
1144 {
1145 	MakeMandatoryControlPoints();
1146 }
1147 
MakeMandatoryControlPoints()1148 void wxDivisionShape::MakeMandatoryControlPoints()
1149 {
1150 	double maxX, maxY;
1151 
1152 	GetBoundingBoxMax(&maxX, &maxY);
1153 	double x = 0.0 , y = 0.0;
1154 	int direction = 0;
1155 	/*
1156 	  if (m_leftSide)
1157 	  {
1158 	    x = (double)(-maxX/2.0);
1159 	    y = 0.0;
1160 	    wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1161 	                                             CONTROL_POINT_HORIZONTAL);
1162 	    m_canvas->AddShape(control);
1163 	    m_controlPoints.Append(control);
1164 	  }
1165 	  if (m_topSide)
1166 	  {
1167 	    x = 0.0;
1168 	    y = (double)(-maxY/2.0);
1169 	    wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1170 	                                             CONTROL_POINT_VERTICAL);
1171 	    m_canvas->AddShape(control);
1172 	    m_controlPoints.Append(control);
1173 	  }
1174 	*/
1175 	switch (m_handleSide)
1176 	{
1177 		case DIVISION_SIDE_LEFT:
1178 		{
1179 			x = (double)(-maxX / 2.0);
1180 			y = 0.0;
1181 			direction = CONTROL_POINT_HORIZONTAL;
1182 			break;
1183 		}
1184 		case DIVISION_SIDE_TOP:
1185 		{
1186 			x = 0.0;
1187 			y = (double)(-maxY / 2.0);
1188 			direction = CONTROL_POINT_VERTICAL;
1189 			break;
1190 		}
1191 		case DIVISION_SIDE_RIGHT:
1192 		{
1193 			x = (double)(maxX / 2.0);
1194 			y = 0.0;
1195 			direction = CONTROL_POINT_HORIZONTAL;
1196 			break;
1197 		}
1198 		case DIVISION_SIDE_BOTTOM:
1199 		{
1200 			x = 0.0;
1201 			y = (double)(maxY / 2.0);
1202 			direction = CONTROL_POINT_VERTICAL;
1203 			break;
1204 		}
1205 		default:
1206 			break;
1207 	}
1208 	if (m_handleSide != DIVISION_SIDE_NONE)
1209 	{
1210 		wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1211 		        direction);
1212 		m_canvas->AddShape(control);
1213 		m_controlPoints.Append(control);
1214 	}
1215 }
1216 
ResetControlPoints()1217 void wxDivisionShape::ResetControlPoints()
1218 {
1219 	ResetMandatoryControlPoints();
1220 }
1221 
ResetMandatoryControlPoints()1222 void wxDivisionShape::ResetMandatoryControlPoints()
1223 {
1224 	if (m_controlPoints.GetCount() < 1)
1225 		return;
1226 
1227 	double maxX, maxY;
1228 
1229 	GetBoundingBoxMax(&maxX, &maxY);
1230 	/*
1231 	  wxNode *node = m_controlPoints.GetFirst();
1232 	  while (node)
1233 	  {
1234 	    wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1235 	    if (control->type == CONTROL_POINT_HORIZONTAL)
1236 	    {
1237 	      control->xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
1238 	    }
1239 	    else if (control->type == CONTROL_POINT_VERTICAL)
1240 	    {
1241 	      control->xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
1242 	    }
1243 	    node = node->GetNext();
1244 	  }
1245 	*/
1246 	wxNode *node = m_controlPoints.GetFirst();
1247 	if ((m_handleSide == DIVISION_SIDE_LEFT) && node)
1248 	{
1249 		wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1250 		control->m_xoffset = (double)(-maxX / 2.0);
1251 		control->m_yoffset = 0.0;
1252 	}
1253 
1254 	if ((m_handleSide == DIVISION_SIDE_TOP) && node)
1255 	{
1256 		wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1257 		control->m_xoffset = 0.0;
1258 		control->m_yoffset = (double)(-maxY / 2.0);
1259 	}
1260 
1261 	if ((m_handleSide == DIVISION_SIDE_RIGHT) && node)
1262 	{
1263 		wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1264 		control->m_xoffset = (double)(maxX / 2.0);
1265 		control->m_yoffset = 0.0;
1266 	}
1267 
1268 	if ((m_handleSide == DIVISION_SIDE_BOTTOM) && node)
1269 	{
1270 		wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1271 		control->m_xoffset = 0.0;
1272 		control->m_yoffset = (double)(maxY / 2.0);
1273 	}
1274 }
1275 
1276 // Adjust a side, returning FALSE if it's not physically possible.
AdjustLeft(double left,bool test)1277 bool wxDivisionShape::AdjustLeft(double left, bool test)
1278 {
1279 	double x2 = (double)(GetX() + (GetWidth() / 2.0));
1280 
1281 	if (left >= x2)
1282 		return FALSE;
1283 	if (test)
1284 		return TRUE;
1285 
1286 	double newW = x2 - left;
1287 	double newX = (double)(left + newW / 2.0);
1288 	SetSize(newW, GetHeight());
1289 
1290 	Move(newX, GetY());
1291 
1292 	if (GetCanvas())
1293 		GetCanvas()->Refresh();
1294 
1295 	return TRUE;
1296 }
1297 
AdjustTop(double top,bool test)1298 bool wxDivisionShape::AdjustTop(double top, bool test)
1299 {
1300 	double y2 = (double)(GetY() + (GetHeight() / 2.0));
1301 
1302 	if (top >= y2)
1303 		return FALSE;
1304 	if (test)
1305 		return TRUE;
1306 
1307 	double newH = y2 - top;
1308 	double newY = (double)(top + newH / 2.0);
1309 	SetSize(GetWidth(), newH);
1310 
1311 	Move(GetX(), newY);
1312 
1313 	if (GetCanvas())
1314 		GetCanvas()->Refresh();
1315 
1316 	return TRUE;
1317 }
1318 
AdjustRight(double right,bool test)1319 bool wxDivisionShape::AdjustRight(double right, bool test)
1320 {
1321 	double x1 = (double)(GetX() - (GetWidth() / 2.0));
1322 
1323 	if (right <= x1)
1324 		return FALSE;
1325 	if (test)
1326 		return TRUE;
1327 
1328 	double newW = right - x1;
1329 	double newX = (double)(x1 + newW / 2.0);
1330 	SetSize(newW, GetHeight());
1331 
1332 	Move(newX, GetY());
1333 
1334 	if (GetCanvas())
1335 		GetCanvas()->Refresh();
1336 
1337 	return TRUE;
1338 }
1339 
AdjustBottom(double bottom,bool test)1340 bool wxDivisionShape::AdjustBottom(double bottom, bool test)
1341 {
1342 	double y1 = (double)(GetY() - (GetHeight() / 2.0));
1343 
1344 	if (bottom <= y1)
1345 		return FALSE;
1346 	if (test)
1347 		return TRUE;
1348 
1349 	double newH = bottom - y1;
1350 	double newY = (double)(y1 + newH / 2.0);
1351 	SetSize(GetWidth(), newH);
1352 
1353 	Move(GetX(), newY);
1354 
1355 	if (GetCanvas())
1356 		GetCanvas()->Refresh();
1357 
1358 	return TRUE;
1359 }
1360 
wxDivisionControlPoint(wxShapeCanvas * the_canvas,wxShape * object,double size,double the_xoffset,double the_yoffset,int the_type)1361 wxDivisionControlPoint::wxDivisionControlPoint(wxShapeCanvas *the_canvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type):
1362 	wxControlPoint(the_canvas, object, size, the_xoffset, the_yoffset, the_type)
1363 {
1364 	SetEraseObject(FALSE);
1365 }
1366 
~wxDivisionControlPoint()1367 wxDivisionControlPoint::~wxDivisionControlPoint()
1368 {
1369 }
1370 
1371 static double originalX = 0.0;
1372 static double originalY = 0.0;
1373 static double originalW = 0.0;
1374 static double originalH = 0.0;
1375 
1376 // Implement resizing of canvas object
OnDragLeft(bool draw,double x,double y,int keys,int attachment)1377 void wxDivisionControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
1378 {
1379 	wxControlPoint::OnDragLeft(draw, x, y, keys, attachment);
1380 }
1381 
OnBeginDragLeft(double x,double y,int keys,int attachment)1382 void wxDivisionControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
1383 {
1384 	wxDivisionShape *division = (wxDivisionShape *)m_shape;
1385 	originalX = division->GetX();
1386 	originalY = division->GetY();
1387 	originalW = division->GetWidth();
1388 	originalH = division->GetHeight();
1389 
1390 	wxControlPoint::OnBeginDragLeft(x, y, keys, attachment);
1391 }
1392 
OnEndDragLeft(double x,double y,int keys,int attachment)1393 void wxDivisionControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
1394 {
1395 	wxControlPoint::OnEndDragLeft(x, y, keys, attachment);
1396 
1397 	wxDivisionShape *division = (wxDivisionShape *)m_shape;
1398 	wxCompositeShape *divisionParent = (wxCompositeShape *)division->GetParent();
1399 
1400 	// Need to check it's within the bounds of the parent composite.
1401 	double x1 = (double)(divisionParent->GetX() - (divisionParent->GetWidth() / 2.0));
1402 	double y1 = (double)(divisionParent->GetY() - (divisionParent->GetHeight() / 2.0));
1403 	double x2 = (double)(divisionParent->GetX() + (divisionParent->GetWidth() / 2.0));
1404 	double y2 = (double)(divisionParent->GetY() + (divisionParent->GetHeight() / 2.0));
1405 
1406 	// Need to check it has not made the division zero or negative width/height
1407 	double dx1 = (double)(division->GetX() - (division->GetWidth() / 2.0));
1408 	double dy1 = (double)(division->GetY() - (division->GetHeight() / 2.0));
1409 	double dx2 = (double)(division->GetX() + (division->GetWidth() / 2.0));
1410 	double dy2 = (double)(division->GetY() + (division->GetHeight() / 2.0));
1411 
1412 	bool success = TRUE;
1413 	switch (division->GetHandleSide())
1414 	{
1415 		case DIVISION_SIDE_LEFT:
1416 		{
1417 			if ((x <= x1) || (x >= x2) || (x >= dx2))
1418 				success = FALSE;
1419 			// Try it out first...
1420 			else if (!division->ResizeAdjoining(DIVISION_SIDE_LEFT, x, TRUE))
1421 				success = FALSE;
1422 			else
1423 				division->ResizeAdjoining(DIVISION_SIDE_LEFT, x, FALSE);
1424 
1425 			break;
1426 		}
1427 		case DIVISION_SIDE_TOP:
1428 		{
1429 			if ((y <= y1) || (y >= y2) || (y >= dy2))
1430 				success = FALSE;
1431 			else if (!division->ResizeAdjoining(DIVISION_SIDE_TOP, y, TRUE))
1432 				success = FALSE;
1433 			else
1434 				division->ResizeAdjoining(DIVISION_SIDE_TOP, y, FALSE);
1435 
1436 			break;
1437 		}
1438 		case DIVISION_SIDE_RIGHT:
1439 		{
1440 			if ((x <= x1) || (x >= x2) || (x <= dx1))
1441 				success = FALSE;
1442 			else if (!division->ResizeAdjoining(DIVISION_SIDE_RIGHT, x, TRUE))
1443 				success = FALSE;
1444 			else
1445 				division->ResizeAdjoining(DIVISION_SIDE_RIGHT, x, FALSE);
1446 
1447 			break;
1448 		}
1449 		case DIVISION_SIDE_BOTTOM:
1450 		{
1451 			if ((y <= y1) || (y >= y2) || (y <= dy1))
1452 				success = FALSE;
1453 			else if (!division->ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, TRUE))
1454 				success = FALSE;
1455 			else
1456 				division->ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, FALSE);
1457 
1458 			break;
1459 		}
1460 	}
1461 	if (!success)
1462 	{
1463 		division->SetSize(originalW, originalH);
1464 		division->Move(originalX, originalY);
1465 	}
1466 
1467 	if (GetCanvas())
1468 		GetCanvas()->Refresh();
1469 
1470 }
1471 
1472 /* Resize adjoining divisions.
1473  *
1474    Behaviour should be as follows:
1475    If right edge moves, find all objects whose left edge
1476    adjoins this object, and move left edge accordingly.
1477    If left..., move ... right.
1478    If top..., move ... bottom.
1479    If bottom..., move top.
1480    If size goes to zero or end position is other side of start position,
1481    resize to original size and return.
1482  */
ResizeAdjoining(int side,double newPos,bool test)1483 bool wxDivisionShape::ResizeAdjoining(int side, double newPos, bool test)
1484 {
1485 	wxCompositeShape *divisionParent = (wxCompositeShape *)GetParent();
1486 	wxNode *node = divisionParent->GetDivisions().GetFirst();
1487 	while (node)
1488 	{
1489 		wxDivisionShape *division = (wxDivisionShape *)node->GetData();
1490 		switch (side)
1491 		{
1492 			case DIVISION_SIDE_LEFT:
1493 			{
1494 				if (division->m_rightSide == this)
1495 				{
1496 					bool success = division->AdjustRight(newPos, test);
1497 					if (!success && test)
1498 						return FALSE;
1499 				}
1500 				break;
1501 			}
1502 			case DIVISION_SIDE_TOP:
1503 			{
1504 				if (division->m_bottomSide == this)
1505 				{
1506 					bool success = division->AdjustBottom(newPos, test);
1507 					if (!success && test)
1508 						return FALSE;
1509 				}
1510 				break;
1511 			}
1512 			case DIVISION_SIDE_RIGHT:
1513 			{
1514 				if (division->m_leftSide == this)
1515 				{
1516 					bool success = division->AdjustLeft(newPos, test);
1517 					if (!success && test)
1518 						return FALSE;
1519 				}
1520 				break;
1521 			}
1522 			case DIVISION_SIDE_BOTTOM:
1523 			{
1524 				if (division->m_topSide == this)
1525 				{
1526 					bool success = division->AdjustTop(newPos, test);
1527 					if (!success && test)
1528 						return FALSE;
1529 				}
1530 				break;
1531 			}
1532 			default:
1533 				break;
1534 		}
1535 		node = node->GetNext();
1536 	}
1537 
1538 	return TRUE;
1539 }
1540 
1541 /*
1542  * Popup menu for editing divisions
1543  *
1544  */
1545 class OGLPopupDivisionMenu : public wxMenu
1546 {
1547 public:
OGLPopupDivisionMenu()1548 	OGLPopupDivisionMenu() : wxMenu()
1549 	{
1550 		Append(DIVISION_MENU_SPLIT_HORIZONTALLY, wxT("Split horizontally"));
1551 		Append(DIVISION_MENU_SPLIT_VERTICALLY, wxT("Split vertically"));
1552 		AppendSeparator();
1553 		Append(DIVISION_MENU_EDIT_LEFT_EDGE, wxT("Edit left edge"));
1554 		Append(DIVISION_MENU_EDIT_TOP_EDGE, wxT("Edit top edge"));
1555 	}
1556 
1557 	void OnMenu(wxCommandEvent &event);
1558 
1559 	DECLARE_EVENT_TABLE()
1560 };
1561 
BEGIN_EVENT_TABLE(OGLPopupDivisionMenu,wxMenu)1562 BEGIN_EVENT_TABLE(OGLPopupDivisionMenu, wxMenu)
1563 	EVT_MENU_RANGE(DIVISION_MENU_SPLIT_HORIZONTALLY,
1564 	               DIVISION_MENU_EDIT_BOTTOM_EDGE,
1565 	               OGLPopupDivisionMenu::OnMenu)
1566 END_EVENT_TABLE()
1567 
1568 
1569 void OGLPopupDivisionMenu::OnMenu(wxCommandEvent &event)
1570 {
1571 	wxDivisionShape *division = (wxDivisionShape *)GetClientData();
1572 	switch (event.GetInt())
1573 	{
1574 		case DIVISION_MENU_SPLIT_HORIZONTALLY:
1575 		{
1576 			division->Divide(wxHORIZONTAL);
1577 			break;
1578 		}
1579 		case DIVISION_MENU_SPLIT_VERTICALLY:
1580 		{
1581 			division->Divide(wxVERTICAL);
1582 			break;
1583 		}
1584 		case DIVISION_MENU_EDIT_LEFT_EDGE:
1585 		{
1586 			division->EditEdge(DIVISION_SIDE_LEFT);
1587 			break;
1588 		}
1589 		case DIVISION_MENU_EDIT_TOP_EDGE:
1590 		{
1591 			division->EditEdge(DIVISION_SIDE_TOP);
1592 			break;
1593 		}
1594 		default:
1595 			break;
1596 	}
1597 }
1598 
EditEdge(int WXUNUSED (side))1599 void wxDivisionShape::EditEdge(int WXUNUSED(side))
1600 {
1601 	wxMessageBox(wxT("EditEdge() not implemented"), wxT("OGL"), wxOK);
1602 
1603 #if 0
1604 	wxBeginBusyCursor();
1605 
1606 	wxPen *currentPen = NULL;
1607 	char **pColour = NULL;
1608 	char **pStyle = NULL;
1609 	if (side == DIVISION_SIDE_LEFT)
1610 	{
1611 		currentPen = m_leftSidePen;
1612 		pColour = &m_leftSideColour;
1613 		pStyle = &m_leftSideStyle;
1614 	}
1615 	else
1616 	{
1617 		currentPen = m_topSidePen;
1618 		pColour = &m_topSideColour;
1619 		pStyle = &m_topSideStyle;
1620 	}
1621 
1622 	GraphicsForm *form = new GraphicsForm("Containers");
1623 	int lineWidth = currentPen->GetWidth();
1624 
1625 	form->Add(wxMakeFormShort("Width", &lineWidth, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
1626 	                          150));
1627 	form->Add(wxMakeFormString("Colour", pColour, wxFORM_CHOICE,
1628 	                           new wxList(wxMakeConstraintStrings(
1629 	                                   "BLACK"            ,
1630 	                                   "BLUE"             ,
1631 	                                   "BROWN"            ,
1632 	                                   "CORAL"            ,
1633 	                                   "CYAN"             ,
1634 	                                   "DARK GREY"        ,
1635 	                                   "DARK GREEN"       ,
1636 	                                   "DIM GREY"         ,
1637 	                                   "GREY"             ,
1638 	                                   "GREEN"            ,
1639 	                                   "LIGHT BLUE"       ,
1640 	                                   "LIGHT GREY"       ,
1641 	                                   "MAGENTA"          ,
1642 	                                   "MAROON"           ,
1643 	                                   "NAVY"             ,
1644 	                                   "ORANGE"           ,
1645 	                                   "PURPLE"           ,
1646 	                                   "RED"              ,
1647 	                                   "TURQUOISE"        ,
1648 	                                   "VIOLET"           ,
1649 	                                   "WHITE"            ,
1650 	                                   "YELLOW"           ,
1651 	                                   NULL),
1652 	                                      NULL), NULL, wxVERTICAL, 150));
1653 	form->Add(wxMakeFormString("Style", pStyle, wxFORM_CHOICE,
1654 	                           new wxList(wxMakeConstraintStrings(
1655 	                                   "Solid"            ,
1656 	                                   "Short Dash"       ,
1657 	                                   "Long Dash"        ,
1658 	                                   "Dot"              ,
1659 	                                   "Dot Dash"         ,
1660 	                                   NULL),
1661 	                                      NULL), NULL, wxVERTICAL, 100));
1662 
1663 	wxDialogBox *dialog = new wxDialogBox(m_canvas->GetParent(), "Division properties", 10, 10, 500, 500);
1664 	if (GraphicsLabelFont)
1665 		dialog->SetLabelFont(GraphicsLabelFont);
1666 	if (GraphicsButtonFont)
1667 		dialog->SetButtonFont(GraphicsButtonFont);
1668 
1669 	form->AssociatePanel(dialog);
1670 	form->dialog = dialog;
1671 
1672 	dialog->Fit();
1673 	dialog->Centre(wxBOTH);
1674 
1675 	wxEndBusyCursor();
1676 	dialog->Show(TRUE);
1677 
1678 	int lineStyle = wxSOLID;
1679 	if (*pStyle)
1680 	{
1681 		if (strcmp(*pStyle, "Solid") == 0)
1682 			lineStyle = wxSOLID;
1683 		else if (strcmp(*pStyle, "Dot") == 0)
1684 			lineStyle = wxDOT;
1685 		else if (strcmp(*pStyle, "Short Dash") == 0)
1686 			lineStyle = wxSHORT_DASH;
1687 		else if (strcmp(*pStyle, "Long Dash") == 0)
1688 			lineStyle = wxLONG_DASH;
1689 		else if (strcmp(*pStyle, "Dot Dash") == 0)
1690 			lineStyle = wxDOT_DASH;
1691 	}
1692 
1693 	wxPen *newPen = wxThePenList->FindOrCreatePen(*pColour, lineWidth, lineStyle);
1694 	if (!pen)
1695 		pen = wxBLACK_PEN;
1696 	if (side == DIVISION_SIDE_LEFT)
1697 		m_leftSidePen = newPen;
1698 	else
1699 		m_topSidePen = newPen;
1700 
1701 	// Need to draw whole image again
1702 	wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent();
1703 	compositeParent->Draw(dc);
1704 #endif
1705 }
1706 
1707 // Popup menu
PopupMenu(double x,double y)1708 void wxDivisionShape::PopupMenu(double x, double y)
1709 {
1710 	wxMenu *oglPopupDivisionMenu = new OGLPopupDivisionMenu;
1711 
1712 	oglPopupDivisionMenu->SetClientData((void *)this);
1713 	if (m_leftSide)
1714 		oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_LEFT_EDGE, TRUE);
1715 	else
1716 		oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_LEFT_EDGE, FALSE);
1717 	if (m_topSide)
1718 		oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_TOP_EDGE, TRUE);
1719 	else
1720 		oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_TOP_EDGE, FALSE);
1721 
1722 	int x1, y1;
1723 	m_canvas->GetViewStart(&x1, &y1);
1724 
1725 	int unit_x, unit_y;
1726 	m_canvas->GetScrollPixelsPerUnit(&unit_x, &unit_y);
1727 
1728 	wxClientDC dc(GetCanvas());
1729 	GetCanvas()->PrepareDC(dc);
1730 
1731 	int mouse_x = (int)(dc.LogicalToDeviceX((long)(x - x1 * unit_x)));
1732 	int mouse_y = (int)(dc.LogicalToDeviceY((long)(y - y1 * unit_y)));
1733 
1734 	m_canvas->PopupMenu(oglPopupDivisionMenu, mouse_x, mouse_y);
1735 	delete oglPopupDivisionMenu;
1736 }
1737 
SetLeftSideColour(const wxString & colour)1738 void wxDivisionShape::SetLeftSideColour(const wxString &colour)
1739 {
1740 	m_leftSideColour = colour;
1741 }
1742 
SetTopSideColour(const wxString & colour)1743 void wxDivisionShape::SetTopSideColour(const wxString &colour)
1744 {
1745 	m_topSideColour = colour;
1746 }
1747 
SetLeftSideStyle(const wxString & style)1748 void wxDivisionShape::SetLeftSideStyle(const wxString &style)
1749 {
1750 	m_leftSideStyle = style;
1751 }
1752 
SetTopSideStyle(const wxString & style)1753 void wxDivisionShape::SetTopSideStyle(const wxString &style)
1754 {
1755 	m_topSideStyle = style;
1756 }
1757 
1758