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