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 ©)
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 ©)
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