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