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