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