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