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