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