]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/ogl/composit.cpp
corrected version number extraction
[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(*wxBLACK, 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(*wxBLACK, 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 wxString cName = wxEmptyString;
697 wxShape *m_constrainingObject = NULL;
698 wxList m_constrainedObjects;
699
700 // Each constraint is stored in the form
701 // (type name id xspacing yspacing m_constrainingObjectId constrainedObjectIdList)
702
703 wxExpr *typeExpr = constraintExpr->Nth(0);
704 wxExpr *nameExpr = constraintExpr->Nth(1);
705 wxExpr *idExpr = constraintExpr->Nth(2);
706 wxExpr *xExpr = constraintExpr->Nth(3);
707 wxExpr *yExpr = constraintExpr->Nth(4);
708 wxExpr *constrainingExpr = constraintExpr->Nth(5);
709 wxExpr *constrainedExpr = constraintExpr->Nth(6);
710
711 int cType = (int)typeExpr->IntegerValue();
712 double cXSpacing = xExpr->RealValue();
713 double cYSpacing = yExpr->RealValue();
714 cName = nameExpr->StringValue();
715 long cId = idExpr->IntegerValue();
716
717 wxExpr *objExpr1 = database->HashFind(_T("node_image"), constrainingExpr->IntegerValue());
718 if (objExpr1 && objExpr1->GetClientData())
719 m_constrainingObject = (wxShape *)objExpr1->GetClientData();
720 else
721 wxLogFatalError(wxT("Object graphics error: Couldn't find constraining image of composite."));
722
723 int i = 0;
724 wxExpr *currentIdExpr = constrainedExpr->Nth(i);
725 while (currentIdExpr)
726 {
727 long currentId = currentIdExpr->IntegerValue();
728 wxExpr *objExpr2 = database->HashFind(_T("node_image"), currentId);
729 if (objExpr2 && objExpr2->GetClientData())
730 {
731 m_constrainedObjects.Append((wxShape *)objExpr2->GetClientData());
732 }
733 else
734 {
735 wxLogFatalError(wxT("Object graphics error: Couldn't find constrained image of composite."));
736 }
737
738 i ++;
739 currentIdExpr = constrainedExpr->Nth(i);
740 }
741 wxOGLConstraint *newConstraint = AddConstraint(cType, m_constrainingObject, m_constrainedObjects);
742 newConstraint->SetSpacing(cXSpacing, cYSpacing);
743 newConstraint->m_constraintId = cId;
744 newConstraint->m_constraintName = cName;
745 constraintNo ++;
746 }
747 }
748 #endif
749
750 // Make this composite into a container by creating one wxDivisionShape
751 void wxCompositeShape::MakeContainer()
752 {
753 wxDivisionShape *division = OnCreateDivision();
754 m_divisions.Append(division);
755 AddChild(division);
756
757 division->SetSize(m_width, m_height);
758
759 wxClientDC dc(GetCanvas());
760 GetCanvas()->PrepareDC(dc);
761
762 division->Move(dc, GetX(), GetY());
763 Recompute();
764 division->Show(true);
765 }
766
767 wxDivisionShape *wxCompositeShape::OnCreateDivision()
768 {
769 return new wxDivisionShape;
770 }
771
772 wxShape *wxCompositeShape::FindContainerImage()
773 {
774 wxNode *node = m_children.GetFirst();
775 while (node)
776 {
777 wxShape *child = (wxShape *)node->GetData();
778 if (!m_divisions.Member(child))
779 return child;
780 node = node->GetNext();
781 }
782 return NULL;
783 }
784
785 // Returns true if division is a descendant of this container
786 bool wxCompositeShape::ContainsDivision(wxDivisionShape *division)
787 {
788 if (m_divisions.Member(division))
789 return true;
790 wxNode *node = m_children.GetFirst();
791 while (node)
792 {
793 wxShape *child = (wxShape *)node->GetData();
794 if (child->IsKindOf(CLASSINFO(wxCompositeShape)))
795 {
796 bool ans = ((wxCompositeShape *)child)->ContainsDivision(division);
797 if (ans)
798 return true;
799 }
800 node = node->GetNext();
801 }
802 return false;
803 }
804
805 /*
806 * Division object
807 *
808 */
809
810 IMPLEMENT_DYNAMIC_CLASS(wxDivisionShape, wxCompositeShape)
811
812 wxDivisionShape::wxDivisionShape()
813 {
814 SetSensitivityFilter(OP_CLICK_LEFT | OP_CLICK_RIGHT | OP_DRAG_RIGHT);
815 SetCentreResize(false);
816 SetAttachmentMode(true);
817 m_leftSide = NULL;
818 m_rightSide = NULL;
819 m_topSide = NULL;
820 m_bottomSide = NULL;
821 m_handleSide = DIVISION_SIDE_NONE;
822 m_leftSidePen = wxBLACK_PEN;
823 m_topSidePen = wxBLACK_PEN;
824 m_leftSideColour = wxT("BLACK");
825 m_topSideColour = wxT("BLACK");
826 m_leftSideStyle = wxT("Solid");
827 m_topSideStyle = wxT("Solid");
828 ClearRegions();
829 }
830
831 wxDivisionShape::~wxDivisionShape()
832 {
833 }
834
835 void wxDivisionShape::OnDraw(wxDC& dc)
836 {
837 dc.SetBrush(* wxTRANSPARENT_BRUSH);
838 dc.SetBackgroundMode(wxTRANSPARENT);
839
840 double x1 = (double)(GetX() - (GetWidth()/2.0));
841 double y1 = (double)(GetY() - (GetHeight()/2.0));
842 double x2 = (double)(GetX() + (GetWidth()/2.0));
843 double y2 = (double)(GetY() + (GetHeight()/2.0));
844
845 // Should subtract 1 pixel if drawing under Windows
846 #ifdef __WXMSW__
847 y2 -= (double)1.0;
848 #endif
849
850 if (m_leftSide)
851 {
852 dc.SetPen(* m_leftSidePen);
853 dc.DrawLine(WXROUND(x1), WXROUND(y2), WXROUND(x1), WXROUND(y1));
854 }
855 if (m_topSide)
856 {
857 dc.SetPen(* m_topSidePen);
858 dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y1));
859 }
860
861 // For testing purposes, draw a rectangle so we know
862 // how big the division is.
863 // SetBrush(* wxCYAN_BRUSH);
864 // wxRectangleShape::OnDraw(dc);
865 }
866
867 void wxDivisionShape::OnDrawContents(wxDC& dc)
868 {
869 wxCompositeShape::OnDrawContents(dc);
870 }
871
872 bool wxDivisionShape::OnMovePre(wxDC& dc, double x, double y, double oldx, double oldy, bool display)
873 {
874 double diffX = x - oldx;
875 double diffY = y - oldy;
876 wxNode *node = m_children.GetFirst();
877 while (node)
878 {
879 wxShape *object = (wxShape *)node->GetData();
880 object->Erase(dc);
881 object->Move(dc, object->GetX() + diffX, object->GetY() + diffY, display);
882 node = node->GetNext();
883 }
884 return true;
885 }
886
887 void wxDivisionShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
888 {
889 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
890 {
891 attachment = 0;
892 double dist;
893 if (m_parent)
894 {
895 m_parent->HitTest(x, y, &attachment, &dist);
896 m_parent->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
897 }
898 return;
899 }
900 wxShape::OnDragLeft(draw, x, y, keys, attachment);
901 }
902
903 void wxDivisionShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
904 {
905 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
906 {
907 attachment = 0;
908 double dist;
909 if (m_parent)
910 {
911 m_parent->HitTest(x, y, &attachment, &dist);
912 m_parent->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
913 }
914 return;
915 }
916
917 wxShape::OnBeginDragLeft(x, y, keys, attachment);
918 }
919
920 void wxDivisionShape::OnEndDragLeft(double x, double y, int keys, int attachment)
921 {
922 m_canvas->ReleaseMouse();
923 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
924 {
925 attachment = 0;
926 double dist;
927 if (m_parent)
928 {
929 m_parent->HitTest(x, y, &attachment, &dist);
930 m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
931 }
932 return;
933 }
934
935 wxClientDC dc(GetCanvas());
936 GetCanvas()->PrepareDC(dc);
937
938 dc.SetLogicalFunction(wxCOPY);
939
940 m_canvas->Snap(&m_xpos, &m_ypos);
941 GetEventHandler()->OnMovePre(dc, x, y, m_oldX, m_oldY);
942
943 ResetControlPoints();
944 Draw(dc);
945 MoveLinks(dc);
946 GetEventHandler()->OnDrawControlPoints(dc);
947
948 if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
949 }
950
951 void wxDivisionShape::SetSize(double w, double h, bool recursive)
952 {
953 m_width = w;
954 m_height = h;
955 wxRectangleShape::SetSize(w, h, recursive);
956 }
957
958 void wxDivisionShape::CalculateSize()
959 {
960 }
961
962 void wxDivisionShape::Copy(wxShape& copy)
963 {
964 wxCompositeShape::Copy(copy);
965
966 wxASSERT( copy.IsKindOf(CLASSINFO(wxDivisionShape)) ) ;
967
968 wxDivisionShape& divisionCopy = (wxDivisionShape&) copy;
969
970 divisionCopy.m_leftSideStyle = m_leftSideStyle;
971 divisionCopy.m_topSideStyle = m_topSideStyle;
972 divisionCopy.m_leftSideColour = m_leftSideColour;
973 divisionCopy.m_topSideColour = m_topSideColour;
974
975 divisionCopy.m_leftSidePen = m_leftSidePen;
976 divisionCopy.m_topSidePen = m_topSidePen;
977 divisionCopy.m_handleSide = m_handleSide;
978
979 // Division geometry copying is handled at the wxCompositeShape level.
980 }
981
982 #if wxUSE_PROLOGIO
983 void wxDivisionShape::WriteAttributes(wxExpr *clause)
984 {
985 wxCompositeShape::WriteAttributes(clause);
986
987 if (m_leftSide)
988 clause->AddAttributeValue(_T("left_side"), (long)m_leftSide->GetId());
989 if (m_topSide)
990 clause->AddAttributeValue(_T("top_side"), (long)m_topSide->GetId());
991 if (m_rightSide)
992 clause->AddAttributeValue(_T("right_side"), (long)m_rightSide->GetId());
993 if (m_bottomSide)
994 clause->AddAttributeValue(_T("bottom_side"), (long)m_bottomSide->GetId());
995
996 clause->AddAttributeValue(_T("handle_side"), (long)m_handleSide);
997 clause->AddAttributeValueString(_T("left_colour"), m_leftSideColour);
998 clause->AddAttributeValueString(_T("top_colour"), m_topSideColour);
999 clause->AddAttributeValueString(_T("left_style"), m_leftSideStyle);
1000 clause->AddAttributeValueString(_T("top_style"), m_topSideStyle);
1001 }
1002
1003 void wxDivisionShape::ReadAttributes(wxExpr *clause)
1004 {
1005 wxCompositeShape::ReadAttributes(clause);
1006
1007 clause->GetAttributeValue(_T("handle_side"), m_handleSide);
1008 clause->GetAttributeValue(_T("left_colour"), m_leftSideColour);
1009 clause->GetAttributeValue(_T("top_colour"), m_topSideColour);
1010 clause->GetAttributeValue(_T("left_style"), m_leftSideStyle);
1011 clause->GetAttributeValue(_T("top_style"), m_topSideStyle);
1012 }
1013 #endif
1014
1015 // Experimental
1016 void wxDivisionShape::OnRightClick(double x, double y, int keys, int attachment)
1017 {
1018 if (keys & KEY_CTRL)
1019 {
1020 PopupMenu(x, y);
1021 }
1022 /*
1023 else if (keys & KEY_SHIFT)
1024 {
1025 if (m_leftSide || m_topSide || m_rightSide || m_bottomSide)
1026 {
1027 if (Selected())
1028 {
1029 Select(false);
1030 GetParent()->Draw(dc);
1031 }
1032 else
1033 Select(true);
1034 }
1035 }
1036 */
1037 else
1038 {
1039 attachment = 0;
1040 double dist;
1041 if (m_parent)
1042 {
1043 m_parent->HitTest(x, y, &attachment, &dist);
1044 m_parent->GetEventHandler()->OnRightClick(x, y, keys, attachment);
1045 }
1046 return;
1047 }
1048 }
1049
1050
1051 // Divide wxHORIZONTALly or wxVERTICALly
1052 bool wxDivisionShape::Divide(int direction)
1053 {
1054 // Calculate existing top-left, bottom-right
1055 double x1 = (double)(GetX() - (GetWidth()/2.0));
1056 double y1 = (double)(GetY() - (GetHeight()/2.0));
1057 wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent();
1058 double oldWidth = GetWidth();
1059 double oldHeight = GetHeight();
1060 if (Selected())
1061 Select(false);
1062
1063 wxClientDC dc(GetCanvas());
1064 GetCanvas()->PrepareDC(dc);
1065
1066 if (direction == wxVERTICAL)
1067 {
1068 // Dividing vertically means notionally putting a horizontal line through it.
1069 // Break existing piece into two.
1070 double newXPos1 = GetX();
1071 double newYPos1 = (double)(y1 + (GetHeight()/4.0));
1072 double newXPos2 = GetX();
1073 double newYPos2 = (double)(y1 + (3.0*GetHeight()/4.0));
1074 wxDivisionShape *newDivision = compositeParent->OnCreateDivision();
1075 newDivision->Show(true);
1076
1077 Erase(dc);
1078
1079 // Anything adjoining the bottom of this division now adjoins the
1080 // bottom of the new division.
1081 wxNode *node = compositeParent->GetDivisions().GetFirst();
1082 while (node)
1083 {
1084 wxDivisionShape *obj = (wxDivisionShape *)node->GetData();
1085 if (obj->GetTopSide() == this)
1086 obj->SetTopSide(newDivision);
1087 node = node->GetNext();
1088 }
1089 newDivision->SetTopSide(this);
1090 newDivision->SetBottomSide(m_bottomSide);
1091 newDivision->SetLeftSide(m_leftSide);
1092 newDivision->SetRightSide(m_rightSide);
1093 m_bottomSide = newDivision;
1094
1095 compositeParent->GetDivisions().Append(newDivision);
1096
1097 // CHANGE: Need to insert this division at start of divisions in the object
1098 // list, because e.g.:
1099 // 1) Add division
1100 // 2) Add contained object
1101 // 3) Add division
1102 // Division is now receiving mouse events _before_ the contained object,
1103 // because it was added last (on top of all others)
1104
1105 // Add after the image that visualizes the container
1106 compositeParent->AddChild(newDivision, compositeParent->FindContainerImage());
1107
1108 m_handleSide = DIVISION_SIDE_BOTTOM;
1109 newDivision->SetHandleSide(DIVISION_SIDE_TOP);
1110
1111 SetSize(oldWidth, (double)(oldHeight/2.0));
1112 Move(dc, newXPos1, newYPos1);
1113
1114 newDivision->SetSize(oldWidth, (double)(oldHeight/2.0));
1115 newDivision->Move(dc, newXPos2, newYPos2);
1116 }
1117 else
1118 {
1119 // Dividing horizontally means notionally putting a vertical line through it.
1120 // Break existing piece into two.
1121 double newXPos1 = (double)(x1 + (GetWidth()/4.0));
1122 double newYPos1 = GetY();
1123 double newXPos2 = (double)(x1 + (3.0*GetWidth()/4.0));
1124 double newYPos2 = GetY();
1125 wxDivisionShape *newDivision = compositeParent->OnCreateDivision();
1126 newDivision->Show(true);
1127
1128 Erase(dc);
1129
1130 // Anything adjoining the left of this division now adjoins the
1131 // left of the new division.
1132 wxNode *node = compositeParent->GetDivisions().GetFirst();
1133 while (node)
1134 {
1135 wxDivisionShape *obj = (wxDivisionShape *)node->GetData();
1136 if (obj->GetLeftSide() == this)
1137 obj->SetLeftSide(newDivision);
1138 node = node->GetNext();
1139 }
1140 newDivision->SetTopSide(m_topSide);
1141 newDivision->SetBottomSide(m_bottomSide);
1142 newDivision->SetLeftSide(this);
1143 newDivision->SetRightSide(m_rightSide);
1144 m_rightSide = newDivision;
1145
1146 compositeParent->GetDivisions().Append(newDivision);
1147 compositeParent->AddChild(newDivision, compositeParent->FindContainerImage());
1148
1149 m_handleSide = DIVISION_SIDE_RIGHT;
1150 newDivision->SetHandleSide(DIVISION_SIDE_LEFT);
1151
1152 SetSize((double)(oldWidth/2.0), oldHeight);
1153 Move(dc, newXPos1, newYPos1);
1154
1155 newDivision->SetSize((double)(oldWidth/2.0), oldHeight);
1156 newDivision->Move(dc, newXPos2, newYPos2);
1157 }
1158 if (compositeParent->Selected())
1159 {
1160 compositeParent->DeleteControlPoints(& dc);
1161 compositeParent->MakeControlPoints();
1162 compositeParent->MakeMandatoryControlPoints();
1163 }
1164 compositeParent->Draw(dc);
1165 return true;
1166 }
1167
1168 // Make one control point for every visible line
1169 void wxDivisionShape::MakeControlPoints()
1170 {
1171 MakeMandatoryControlPoints();
1172 }
1173
1174 void wxDivisionShape::MakeMandatoryControlPoints()
1175 {
1176 double maxX, maxY;
1177
1178 GetBoundingBoxMax(&maxX, &maxY);
1179 double x = 0.0 , y = 0.0;
1180 int direction = 0;
1181 /*
1182 if (m_leftSide)
1183 {
1184 x = (double)(-maxX/2.0);
1185 y = 0.0;
1186 wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1187 CONTROL_POINT_HORIZONTAL);
1188 m_canvas->AddShape(control);
1189 m_controlPoints.Append(control);
1190 }
1191 if (m_topSide)
1192 {
1193 x = 0.0;
1194 y = (double)(-maxY/2.0);
1195 wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1196 CONTROL_POINT_VERTICAL);
1197 m_canvas->AddShape(control);
1198 m_controlPoints.Append(control);
1199 }
1200 */
1201 switch (m_handleSide)
1202 {
1203 case DIVISION_SIDE_LEFT:
1204 {
1205 x = (double)(-maxX/2.0);
1206 y = 0.0;
1207 direction = CONTROL_POINT_HORIZONTAL;
1208 break;
1209 }
1210 case DIVISION_SIDE_TOP:
1211 {
1212 x = 0.0;
1213 y = (double)(-maxY/2.0);
1214 direction = CONTROL_POINT_VERTICAL;
1215 break;
1216 }
1217 case DIVISION_SIDE_RIGHT:
1218 {
1219 x = (double)(maxX/2.0);
1220 y = 0.0;
1221 direction = CONTROL_POINT_HORIZONTAL;
1222 break;
1223 }
1224 case DIVISION_SIDE_BOTTOM:
1225 {
1226 x = 0.0;
1227 y = (double)(maxY/2.0);
1228 direction = CONTROL_POINT_VERTICAL;
1229 break;
1230 }
1231 default:
1232 break;
1233 }
1234 if (m_handleSide != DIVISION_SIDE_NONE)
1235 {
1236 wxDivisionControlPoint *control = new wxDivisionControlPoint(m_canvas, this, CONTROL_POINT_SIZE, x, y,
1237 direction);
1238 m_canvas->AddShape(control);
1239 m_controlPoints.Append(control);
1240 }
1241 }
1242
1243 void wxDivisionShape::ResetControlPoints()
1244 {
1245 ResetMandatoryControlPoints();
1246 }
1247
1248 void wxDivisionShape::ResetMandatoryControlPoints()
1249 {
1250 if (m_controlPoints.GetCount() < 1)
1251 return;
1252
1253 double maxX, maxY;
1254
1255 GetBoundingBoxMax(&maxX, &maxY);
1256 /*
1257 wxNode *node = m_controlPoints.GetFirst();
1258 while (node)
1259 {
1260 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1261 if (control->type == CONTROL_POINT_HORIZONTAL)
1262 {
1263 control->xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
1264 }
1265 else if (control->type == CONTROL_POINT_VERTICAL)
1266 {
1267 control->xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
1268 }
1269 node = node->GetNext();
1270 }
1271 */
1272 wxNode *node = m_controlPoints.GetFirst();
1273 if ((m_handleSide == DIVISION_SIDE_LEFT) && node)
1274 {
1275 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1276 control->m_xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
1277 }
1278
1279 if ((m_handleSide == DIVISION_SIDE_TOP) && node)
1280 {
1281 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1282 control->m_xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
1283 }
1284
1285 if ((m_handleSide == DIVISION_SIDE_RIGHT) && node)
1286 {
1287 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1288 control->m_xoffset = (double)(maxX/2.0); control->m_yoffset = 0.0;
1289 }
1290
1291 if ((m_handleSide == DIVISION_SIDE_BOTTOM) && node)
1292 {
1293 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->GetData();
1294 control->m_xoffset = 0.0; control->m_yoffset = (double)(maxY/2.0);
1295 }
1296 }
1297
1298 // Adjust a side, returning false if it's not physically possible.
1299 bool wxDivisionShape::AdjustLeft(double left, bool test)
1300 {
1301 double x2 = (double)(GetX() + (GetWidth()/2.0));
1302
1303 if (left >= x2)
1304 return false;
1305 if (test)
1306 return true;
1307
1308 double newW = x2 - left;
1309 double newX = (double)(left + newW/2.0);
1310 SetSize(newW, GetHeight());
1311
1312 wxClientDC dc(GetCanvas());
1313 GetCanvas()->PrepareDC(dc);
1314
1315 Move(dc, newX, GetY());
1316
1317 return true;
1318 }
1319
1320 bool wxDivisionShape::AdjustTop(double top, bool test)
1321 {
1322 double y2 = (double)(GetY() + (GetHeight()/2.0));
1323
1324 if (top >= y2)
1325 return false;
1326 if (test)
1327 return true;
1328
1329 double newH = y2 - top;
1330 double newY = (double)(top + newH/2.0);
1331 SetSize(GetWidth(), newH);
1332
1333 wxClientDC dc(GetCanvas());
1334 GetCanvas()->PrepareDC(dc);
1335
1336 Move(dc, GetX(), newY);
1337
1338 return true;
1339 }
1340
1341 bool wxDivisionShape::AdjustRight(double right, bool test)
1342 {
1343 double x1 = (double)(GetX() - (GetWidth()/2.0));
1344
1345 if (right <= x1)
1346 return false;
1347 if (test)
1348 return true;
1349
1350 double newW = right - x1;
1351 double newX = (double)(x1 + newW/2.0);
1352 SetSize(newW, GetHeight());
1353
1354 wxClientDC dc(GetCanvas());
1355 GetCanvas()->PrepareDC(dc);
1356
1357 Move(dc, newX, GetY());
1358
1359 return true;
1360 }
1361
1362 bool wxDivisionShape::AdjustBottom(double bottom, bool test)
1363 {
1364 double y1 = (double)(GetY() - (GetHeight()/2.0));
1365
1366 if (bottom <= y1)
1367 return false;
1368 if (test)
1369 return true;
1370
1371 double newH = bottom - y1;
1372 double newY = (double)(y1 + newH/2.0);
1373 SetSize(GetWidth(), newH);
1374
1375 wxClientDC dc(GetCanvas());
1376 GetCanvas()->PrepareDC(dc);
1377
1378 Move(dc, GetX(), newY);
1379
1380 return true;
1381 }
1382
1383 wxDivisionControlPoint::wxDivisionControlPoint(wxShapeCanvas *the_canvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type):
1384 wxControlPoint(the_canvas, object, size, the_xoffset, the_yoffset, the_type)
1385 {
1386 SetEraseObject(false);
1387 }
1388
1389 wxDivisionControlPoint::~wxDivisionControlPoint()
1390 {
1391 }
1392
1393 static double originalX = 0.0;
1394 static double originalY = 0.0;
1395 static double originalW = 0.0;
1396 static double originalH = 0.0;
1397
1398 // Implement resizing of canvas object
1399 void wxDivisionControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
1400 {
1401 wxControlPoint::OnDragLeft(draw, x, y, keys, attachment);
1402 }
1403
1404 void wxDivisionControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
1405 {
1406 wxDivisionShape *division = (wxDivisionShape *)m_shape;
1407 originalX = division->GetX();
1408 originalY = division->GetY();
1409 originalW = division->GetWidth();
1410 originalH = division->GetHeight();
1411
1412 wxControlPoint::OnBeginDragLeft(x, y, keys, attachment);
1413 }
1414
1415 void wxDivisionControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
1416 {
1417 wxControlPoint::OnEndDragLeft(x, y, keys, attachment);
1418
1419 wxClientDC dc(GetCanvas());
1420 GetCanvas()->PrepareDC(dc);
1421
1422 wxDivisionShape *division = (wxDivisionShape *)m_shape;
1423 wxCompositeShape *divisionParent = (wxCompositeShape *)division->GetParent();
1424
1425 // Need to check it's within the bounds of the parent composite.
1426 double x1 = (double)(divisionParent->GetX() - (divisionParent->GetWidth()/2.0));
1427 double y1 = (double)(divisionParent->GetY() - (divisionParent->GetHeight()/2.0));
1428 double x2 = (double)(divisionParent->GetX() + (divisionParent->GetWidth()/2.0));
1429 double y2 = (double)(divisionParent->GetY() + (divisionParent->GetHeight()/2.0));
1430
1431 // Need to check it has not made the division zero or negative width/height
1432 double dx1 = (double)(division->GetX() - (division->GetWidth()/2.0));
1433 double dy1 = (double)(division->GetY() - (division->GetHeight()/2.0));
1434 double dx2 = (double)(division->GetX() + (division->GetWidth()/2.0));
1435 double dy2 = (double)(division->GetY() + (division->GetHeight()/2.0));
1436
1437 bool success = true;
1438 switch (division->GetHandleSide())
1439 {
1440 case DIVISION_SIDE_LEFT:
1441 {
1442 if ((x <= x1) || (x >= x2) || (x >= dx2))
1443 success = false;
1444 // Try it out first...
1445 else if (!division->ResizeAdjoining(DIVISION_SIDE_LEFT, x, true))
1446 success = false;
1447 else
1448 division->ResizeAdjoining(DIVISION_SIDE_LEFT, x, false);
1449
1450 break;
1451 }
1452 case DIVISION_SIDE_TOP:
1453 {
1454 if ((y <= y1) || (y >= y2) || (y >= dy2))
1455 success = false;
1456 else if (!division->ResizeAdjoining(DIVISION_SIDE_TOP, y, true))
1457 success = false;
1458 else
1459 division->ResizeAdjoining(DIVISION_SIDE_TOP, y, false);
1460
1461 break;
1462 }
1463 case DIVISION_SIDE_RIGHT:
1464 {
1465 if ((x <= x1) || (x >= x2) || (x <= dx1))
1466 success = false;
1467 else if (!division->ResizeAdjoining(DIVISION_SIDE_RIGHT, x, true))
1468 success = false;
1469 else
1470 division->ResizeAdjoining(DIVISION_SIDE_RIGHT, x, false);
1471
1472 break;
1473 }
1474 case DIVISION_SIDE_BOTTOM:
1475 {
1476 if ((y <= y1) || (y >= y2) || (y <= dy1))
1477 success = false;
1478 else if (!division->ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, true))
1479 success = false;
1480 else
1481 division->ResizeAdjoining(DIVISION_SIDE_BOTTOM, y, false);
1482
1483 break;
1484 }
1485 }
1486 if (!success)
1487 {
1488 division->SetSize(originalW, originalH);
1489 division->Move(dc, originalX, originalY);
1490 }
1491 divisionParent->Draw(dc);
1492 division->GetEventHandler()->OnDrawControlPoints(dc);
1493 }
1494
1495 /* Resize adjoining divisions.
1496 *
1497 Behaviour should be as follows:
1498 If right edge moves, find all objects whose left edge
1499 adjoins this object, and move left edge accordingly.
1500 If left..., move ... right.
1501 If top..., move ... bottom.
1502 If bottom..., move top.
1503 If size goes to zero or end position is other side of start position,
1504 resize to original size and return.
1505 */
1506 bool wxDivisionShape::ResizeAdjoining(int side, double newPos, bool test)
1507 {
1508 wxCompositeShape *divisionParent = (wxCompositeShape *)GetParent();
1509 wxNode *node = divisionParent->GetDivisions().GetFirst();
1510 while (node)
1511 {
1512 wxDivisionShape *division = (wxDivisionShape *)node->GetData();
1513 switch (side)
1514 {
1515 case DIVISION_SIDE_LEFT:
1516 {
1517 if (division->m_rightSide == this)
1518 {
1519 bool success = division->AdjustRight(newPos, test);
1520 if (!success && test)
1521 return false;
1522 }
1523 break;
1524 }
1525 case DIVISION_SIDE_TOP:
1526 {
1527 if (division->m_bottomSide == this)
1528 {
1529 bool success = division->AdjustBottom(newPos, test);
1530 if (!success && test)
1531 return false;
1532 }
1533 break;
1534 }
1535 case DIVISION_SIDE_RIGHT:
1536 {
1537 if (division->m_leftSide == this)
1538 {
1539 bool success = division->AdjustLeft(newPos, test);
1540 if (!success && test)
1541 return false;
1542 }
1543 break;
1544 }
1545 case DIVISION_SIDE_BOTTOM:
1546 {
1547 if (division->m_topSide == this)
1548 {
1549 bool success = division->AdjustTop(newPos, test);
1550 if (!success && test)
1551 return false;
1552 }
1553 break;
1554 }
1555 default:
1556 break;
1557 }
1558 node = node->GetNext();
1559 }
1560
1561 return true;
1562 }
1563
1564 /*
1565 * Popup menu for editing divisions
1566 *
1567 */
1568 class OGLPopupDivisionMenu : public wxMenu {
1569 public:
1570 OGLPopupDivisionMenu() : wxMenu() {
1571 Append(DIVISION_MENU_SPLIT_HORIZONTALLY, wxT("Split horizontally"));
1572 Append(DIVISION_MENU_SPLIT_VERTICALLY, wxT("Split vertically"));
1573 AppendSeparator();
1574 Append(DIVISION_MENU_EDIT_LEFT_EDGE, wxT("Edit left edge"));
1575 Append(DIVISION_MENU_EDIT_TOP_EDGE, wxT("Edit top edge"));
1576 }
1577
1578 void OnMenu(wxCommandEvent& event);
1579
1580 DECLARE_EVENT_TABLE()
1581 };
1582
1583 BEGIN_EVENT_TABLE(OGLPopupDivisionMenu, wxMenu)
1584 EVT_MENU_RANGE(DIVISION_MENU_SPLIT_HORIZONTALLY,
1585 DIVISION_MENU_EDIT_BOTTOM_EDGE,
1586 OGLPopupDivisionMenu::OnMenu)
1587 END_EVENT_TABLE()
1588
1589
1590 void OGLPopupDivisionMenu::OnMenu(wxCommandEvent& event)
1591 {
1592 wxDivisionShape *division = (wxDivisionShape *)GetClientData();
1593 switch (event.GetInt())
1594 {
1595 case DIVISION_MENU_SPLIT_HORIZONTALLY:
1596 {
1597 division->Divide(wxHORIZONTAL);
1598 break;
1599 }
1600 case DIVISION_MENU_SPLIT_VERTICALLY:
1601 {
1602 division->Divide(wxVERTICAL);
1603 break;
1604 }
1605 case DIVISION_MENU_EDIT_LEFT_EDGE:
1606 {
1607 division->EditEdge(DIVISION_SIDE_LEFT);
1608 break;
1609 }
1610 case DIVISION_MENU_EDIT_TOP_EDGE:
1611 {
1612 division->EditEdge(DIVISION_SIDE_TOP);
1613 break;
1614 }
1615 default:
1616 break;
1617 }
1618 }
1619
1620 void wxDivisionShape::EditEdge(int WXUNUSED(side))
1621 {
1622 wxMessageBox(wxT("EditEdge() not implemented"), wxT("OGL"), wxOK);
1623
1624 #if 0
1625 wxBeginBusyCursor();
1626
1627 wxPen *currentPen = NULL;
1628 char **pColour = NULL;
1629 char **pStyle = NULL;
1630 if (side == DIVISION_SIDE_LEFT)
1631 {
1632 currentPen = m_leftSidePen;
1633 pColour = &m_leftSideColour;
1634 pStyle = &m_leftSideStyle;
1635 }
1636 else
1637 {
1638 currentPen = m_topSidePen;
1639 pColour = &m_topSideColour;
1640 pStyle = &m_topSideStyle;
1641 }
1642
1643 GraphicsForm *form = new GraphicsForm("Containers");
1644 int lineWidth = currentPen->GetWidth();
1645
1646 form->Add(wxMakeFormShort("Width", &lineWidth, wxFORM_DEFAULT, NULL, NULL, wxVERTICAL,
1647 150));
1648 form->Add(wxMakeFormString("Colour", pColour, wxFORM_CHOICE,
1649 new wxList(wxMakeConstraintStrings(
1650 "BLACK" ,
1651 "BLUE" ,
1652 "BROWN" ,
1653 "CORAL" ,
1654 "CYAN" ,
1655 "DARK GREY" ,
1656 "DARK GREEN" ,
1657 "DIM GREY" ,
1658 "GREY" ,
1659 "GREEN" ,
1660 "LIGHT BLUE" ,
1661 "LIGHT GREY" ,
1662 "MAGENTA" ,
1663 "MAROON" ,
1664 "NAVY" ,
1665 "ORANGE" ,
1666 "PURPLE" ,
1667 "RED" ,
1668 "TURQUOISE" ,
1669 "VIOLET" ,
1670 "WHITE" ,
1671 "YELLOW" ,
1672 NULL),
1673 NULL), NULL, wxVERTICAL, 150));
1674 form->Add(wxMakeFormString("Style", pStyle, wxFORM_CHOICE,
1675 new wxList(wxMakeConstraintStrings(
1676 "Solid" ,
1677 "Short Dash" ,
1678 "Long Dash" ,
1679 "Dot" ,
1680 "Dot Dash" ,
1681 NULL),
1682 NULL), NULL, wxVERTICAL, 100));
1683
1684 wxDialogBox *dialog = new wxDialogBox(m_canvas->GetParent(), "Division properties", 10, 10, 500, 500);
1685 if (GraphicsLabelFont)
1686 dialog->SetLabelFont(GraphicsLabelFont);
1687 if (GraphicsButtonFont)
1688 dialog->SetButtonFont(GraphicsButtonFont);
1689
1690 form->AssociatePanel(dialog);
1691 form->dialog = dialog;
1692
1693 dialog->Fit();
1694 dialog->Centre(wxBOTH);
1695
1696 wxEndBusyCursor();
1697 dialog->Show(true);
1698
1699 int lineStyle = wxSOLID;
1700 if (*pStyle)
1701 {
1702 if (strcmp(*pStyle, "Solid") == 0)
1703 lineStyle = wxSOLID;
1704 else if (strcmp(*pStyle, "Dot") == 0)
1705 lineStyle = wxDOT;
1706 else if (strcmp(*pStyle, "Short Dash") == 0)
1707 lineStyle = wxSHORT_DASH;
1708 else if (strcmp(*pStyle, "Long Dash") == 0)
1709 lineStyle = wxLONG_DASH;
1710 else if (strcmp(*pStyle, "Dot Dash") == 0)
1711 lineStyle = wxDOT_DASH;
1712 }
1713
1714 wxPen *newPen = wxThePenList->FindOrCreatePen(*pColour, lineWidth, lineStyle);
1715 if (!pen)
1716 pen = wxBLACK_PEN;
1717 if (side == DIVISION_SIDE_LEFT)
1718 m_leftSidePen = newPen;
1719 else
1720 m_topSidePen = newPen;
1721
1722 // Need to draw whole image again
1723 wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent();
1724 compositeParent->Draw(dc);
1725 #endif
1726 }
1727
1728 // Popup menu
1729 void wxDivisionShape::PopupMenu(double x, double y)
1730 {
1731 wxMenu* oglPopupDivisionMenu = new OGLPopupDivisionMenu;
1732
1733 oglPopupDivisionMenu->SetClientData((void *)this);
1734 if (m_leftSide)
1735 oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_LEFT_EDGE, true);
1736 else
1737 oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_LEFT_EDGE, false);
1738 if (m_topSide)
1739 oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_TOP_EDGE, true);
1740 else
1741 oglPopupDivisionMenu->Enable(DIVISION_MENU_EDIT_TOP_EDGE, false);
1742
1743 int x1, y1;
1744 m_canvas->GetViewStart(&x1, &y1);
1745
1746 int unit_x, unit_y;
1747 m_canvas->GetScrollPixelsPerUnit(&unit_x, &unit_y);
1748
1749 wxClientDC dc(GetCanvas());
1750 GetCanvas()->PrepareDC(dc);
1751
1752 int mouse_x = (int)(dc.LogicalToDeviceX((long)(x - x1*unit_x)));
1753 int mouse_y = (int)(dc.LogicalToDeviceY((long)(y - y1*unit_y)));
1754
1755 m_canvas->PopupMenu(oglPopupDivisionMenu, mouse_x, mouse_y);
1756 delete oglPopupDivisionMenu;
1757 }
1758
1759 void wxDivisionShape::SetLeftSideColour(const wxString& colour)
1760 {
1761 m_leftSideColour = colour;
1762 }
1763
1764 void wxDivisionShape::SetTopSideColour(const wxString& colour)
1765 {
1766 m_topSideColour = colour;
1767 }
1768
1769 void wxDivisionShape::SetLeftSideStyle(const wxString& style)
1770 {
1771 m_leftSideStyle = style;
1772 }
1773
1774 void wxDivisionShape::SetTopSideStyle(const wxString& style)
1775 {
1776 m_topSideStyle = style;
1777 }
1778