]> git.saurik.com Git - wxWidgets.git/blame - utils/ogl/src/composit.cpp
Added SetFont to most controls and controls sample
[wxWidgets.git] / utils / ogl / src / composit.cpp
CommitLineData
0fc1a713
JS
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.
40wxExprDatabase *GlobalwxExprDatabase = NULL;
41
42// Popup menu for editing divisions
43wxMenu *oglPopupDivisionMenu = NULL;
44
45/*
46 * Division control point
47 */
48
49class wxDivisionControlPoint: public wxControlPoint
50{
51 DECLARE_DYNAMIC_CLASS(wxDivisionControlPoint)
52 public:
53 wxDivisionControlPoint() {}
42cfaf8c 54 wxDivisionControlPoint(wxShapeCanvas *the_canvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type);
0fc1a713
JS
55 ~wxDivisionControlPoint();
56
42cfaf8c
JS
57 void OnDragLeft(bool draw, double x, double y, int keys=0, int attachment = 0);
58 void OnBeginDragLeft(double x, double y, int keys=0, int attachment = 0);
59 void OnEndDragLeft(double x, double y, int keys=0, int attachment = 0);
0fc1a713
JS
60};
61
62IMPLEMENT_DYNAMIC_CLASS(wxDivisionControlPoint, wxControlPoint)
63
64/*
65 * Composite object
66 *
67 */
68
69IMPLEMENT_DYNAMIC_CLASS(wxCompositeShape, wxRectangleShape)
70
71wxCompositeShape::wxCompositeShape(): wxRectangleShape(10.0, 10.0)
72{
73// selectable = FALSE;
74 m_oldX = m_xpos;
75 m_oldY = m_ypos;
76}
77
78wxCompositeShape::~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
98void wxCompositeShape::OnDraw(wxDC& dc)
99{
42cfaf8c
JS
100 double x1 = (double)(m_xpos - m_width/2.0);
101 double y1 = (double)(m_ypos - m_height/2.0);
0fc1a713
JS
102
103 if (m_shadowMode != SHADOW_NONE)
104 {
105 if (m_shadowBrush)
106 dc.SetBrush(m_shadowBrush);
42cfaf8c 107 dc.SetPen(g_oglTransparentPen);
0fc1a713
JS
108
109 if (m_cornerRadius != 0.0)
42cfaf8c
JS
110 dc.DrawRoundedRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY),
111 WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
0fc1a713 112 else
42cfaf8c 113 dc.DrawRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), WXROUND(m_width), WXROUND(m_height));
0fc1a713
JS
114 }
115}
116
117void 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
42cfaf8c 130bool wxCompositeShape::OnMovePre(wxDC& dc, double x, double y, double oldx, double oldy, bool display)
0fc1a713 131{
42cfaf8c
JS
132 double diffX = x - oldx;
133 double diffY = y - oldy;
0fc1a713
JS
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
147void 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
42cfaf8c
JS
159static double objectStartX = 0.0;
160static double objectStartY = 0.0;
0fc1a713 161
42cfaf8c 162void wxCompositeShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
0fc1a713 163{
42cfaf8c
JS
164 double xx = x;
165 double yy = y;
0fc1a713 166 m_canvas->Snap(&xx, &yy);
42cfaf8c
JS
167 double offsetX = xx - objectStartX;
168 double offsetY = yy - objectStartY;
0fc1a713
JS
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
42cfaf8c 182void wxCompositeShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
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
42cfaf8c
JS
199 double xx = x;
200 double yy = y;
0fc1a713 201 m_canvas->Snap(&xx, &yy);
42cfaf8c
JS
202 double offsetX = xx - objectStartX;
203 double offsetY = yy - objectStartY;
0fc1a713
JS
204
205 GetEventHandler()->OnDrawOutline(dc, GetX() + offsetX, GetY() + offsetY, GetWidth(), GetHeight());
206
207// wxShape::OnBeginDragLeft(x, y, keys, attachment);
208}
209
42cfaf8c 210void wxCompositeShape::OnEndDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
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);
42cfaf8c
JS
226 double xx = x;
227 double yy = y;
0fc1a713 228 m_canvas->Snap(&xx, &yy);
42cfaf8c
JS
229 double offsetX = xx - objectStartX;
230 double offsetY = yy - objectStartY;
0fc1a713
JS
231
232 Move(dc, GetX() + offsetX, GetY() + offsetY);
233
234 if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
235}
236
42cfaf8c 237void wxCompositeShape::OnRightClick(double x, double y, int keys, int attachment)
0fc1a713
JS
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;
42cfaf8c 249 double dist = 0.0;
0fc1a713
JS
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
42cfaf8c 261void wxCompositeShape::SetSize(double w, double h, bool recursive)
0fc1a713
JS
262{
263 SetAttachmentSize(w, h);
264
42cfaf8c
JS
265 double xScale = (double)(w/(wxMax(1.0, GetWidth())));
266 double yScale = (double)(h/(wxMax(1.0, GetHeight())));
0fc1a713
JS
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
42cfaf8c 278 double xBound, yBound;
0fc1a713
JS
279 while (node)
280 {
281 wxShape *object = (wxShape *)node->Data();
282
283 // Scale the position first
42cfaf8c
JS
284 double newX = (double)(((object->GetX() - GetX())*xScale) + GetX());
285 double newY = (double)(((object->GetY() - GetY())*yScale) + GetY());
0fc1a713
JS
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
300void 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
313void wxCompositeShape::RemoveChild(wxShape *child)
314{
315 m_children.DeleteObject(child);
316 m_divisions.DeleteObject(child);
317 RemoveChildFromConstraints(child);
318 child->SetParent(NULL);
319}
320
321void 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
339void 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
2bb0cd28 363void wxCompositeShape::Copy(wxShape& copy)
0fc1a713
JS
364{
365 wxRectangleShape::Copy(copy);
366
2bb0cd28
JS
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
42cfaf8c 372 oglObjectCopyMapping.Append((long)this, &compositeCopy);
0fc1a713
JS
373
374 // Copy the children
375 wxNode *node = m_children.First();
376 while (node)
377 {
378 wxShape *object = (wxShape *)node->Data();
2bb0cd28 379 wxShape *newObject = object->CreateNewCopy(FALSE, FALSE);
0fc1a713
JS
380 if (newObject->GetId() == 0)
381 newObject->SetId(NewId());
382
2bb0cd28
JS
383 newObject->SetParent(&compositeCopy);
384 compositeCopy.m_children.Append(newObject);
0fc1a713
JS
385
386 // Some m_children may be divisions
387 if (m_divisions.Member(object))
2bb0cd28 388 compositeCopy.m_divisions.Append(newObject);
0fc1a713 389
42cfaf8c 390 oglObjectCopyMapping.Append((long)object, newObject);
0fc1a713
JS
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
42cfaf8c 401 wxShape *newConstraining = (wxShape *)(oglObjectCopyMapping.Find((long)constraint->m_constrainingObject)->Data());
0fc1a713
JS
402
403 wxList newConstrainedList;
404 wxNode *node2 = constraint->m_constrainedObjects.First();
405 while (node2)
406 {
407 wxShape *constrainedObject = (wxShape *)node2->Data();
42cfaf8c 408 wxShape *newConstrained = (wxShape *)(oglObjectCopyMapping.Find((long)constrainedObject)->Data());
0fc1a713
JS
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);
2bb0cd28 421 compositeCopy.m_constraints.Append(newConstraint);
0fc1a713
JS
422
423 node = node->Next();
424 }
425
2bb0cd28 426 // Now compositeCopy the division geometry
0fc1a713
JS
427 node = m_divisions.First();
428 while (node)
429 {
430 wxDivisionShape *division = (wxDivisionShape *)node->Data();
42cfaf8c 431 wxNode *node1 = oglObjectCopyMapping.Find((long)division);
0fc1a713
JS
432 wxNode *leftNode = NULL;
433 wxNode *topNode = NULL;
434 wxNode *rightNode = NULL;
435 wxNode *bottomNode = NULL;
436 if (division->GetLeftSide())
42cfaf8c 437 leftNode = oglObjectCopyMapping.Find((long)division->GetLeftSide());
0fc1a713 438 if (division->GetTopSide())
42cfaf8c 439 topNode = oglObjectCopyMapping.Find((long)division->GetTopSide());
0fc1a713 440 if (division->GetRightSide())
42cfaf8c 441 rightNode = oglObjectCopyMapping.Find((long)division->GetRightSide());
0fc1a713 442 if (division->GetBottomSide())
42cfaf8c 443 bottomNode = oglObjectCopyMapping.Find((long)division->GetBottomSide());
0fc1a713
JS
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
0fc1a713
JS
460OGLConstraint *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
468OGLConstraint *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
477OGLConstraint *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
488OGLConstraint *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
522void wxCompositeShape::DeleteConstraint(OGLConstraint *constraint)
523{
524 m_constraints.DeleteObject(constraint);
525 delete constraint;
526}
527
528void wxCompositeShape::CalculateSize()
529{
42cfaf8c
JS
530 double maxX = (double) -999999.9;
531 double maxY = (double) -999999.9;
532 double minX = (double) 999999.9;
533 double minY = (double) 999999.9;
0fc1a713 534
42cfaf8c 535 double w, h;
0fc1a713
JS
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)
42cfaf8c 547 maxX = (double)(object->GetX() + (w/2.0));
0fc1a713 548 if ((object->GetX() - (w/2.0)) < minX)
42cfaf8c 549 minX = (double)(object->GetX() - (w/2.0));
0fc1a713 550 if ((object->GetY() + (h/2.0)) > maxY)
42cfaf8c 551 maxY = (double)(object->GetY() + (h/2.0));
0fc1a713 552 if ((object->GetY() - (h/2.0)) < minY)
42cfaf8c 553 minY = (double)(object->GetY() - (h/2.0));
0fc1a713
JS
554
555 node = node->Next();
556 }
557 m_width = maxX - minX;
558 m_height = maxY - minY;
42cfaf8c
JS
559 m_xpos = (double)(m_width/2.0 + minX);
560 m_ypos = (double)(m_height/2.0 + minY);
0fc1a713
JS
561}
562
563bool 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
581bool 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
606void 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.
677void wxCompositeShape::ReadPrologAttributes(wxExpr *clause)
678{
679 wxRectangleShape::ReadPrologAttributes(clause);
680
681// clause->GetAttributeValue("selectable", selectable);
682}
683
684void 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;
42cfaf8c
JS
702 double cXSpacing = 0.0;
703 double cYSpacing = 0.0;
0fc1a713
JS
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
760void 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
776wxDivisionShape *wxCompositeShape::OnCreateDivision()
777{
778 return new wxDivisionShape;
779}
780
781wxShape *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
795bool 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
819IMPLEMENT_DYNAMIC_CLASS(wxDivisionShape, wxCompositeShape)
820
821wxDivisionShape::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
840wxDivisionShape::~wxDivisionShape()
841{
842}
843
844void wxDivisionShape::OnDraw(wxDC& dc)
845{
846 dc.SetBrush(wxTRANSPARENT_BRUSH);
847 dc.SetBackgroundMode(wxTRANSPARENT);
848
42cfaf8c
JS
849 double x1 = (double)(GetX() - (GetWidth()/2.0));
850 double y1 = (double)(GetY() - (GetHeight()/2.0));
851 double x2 = (double)(GetX() + (GetWidth()/2.0));
852 double y2 = (double)(GetY() + (GetHeight()/2.0));
0fc1a713
JS
853
854 // Should subtract 1 pixel if drawing under Windows
855#ifdef __WXMSW__
42cfaf8c 856 y2 -= (double)1.0;
0fc1a713
JS
857#endif
858
859 if (m_leftSide)
860 {
861 dc.SetPen(m_leftSidePen);
42cfaf8c 862 dc.DrawLine(WXROUND(x1), WXROUND(y2), WXROUND(x1), WXROUND(y1));
0fc1a713
JS
863 }
864 if (m_topSide)
865 {
866 dc.SetPen(m_topSidePen);
42cfaf8c 867 dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y1));
0fc1a713
JS
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
876void wxDivisionShape::OnDrawContents(wxDC& dc)
877{
878 wxCompositeShape::OnDrawContents(dc);
879}
880
42cfaf8c 881bool wxDivisionShape::OnMovePre(wxDC& dc, double x, double y, double oldx, double oldy, bool display)
0fc1a713 882{
42cfaf8c
JS
883 double diffX = x - oldx;
884 double diffY = y - oldy;
0fc1a713
JS
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
42cfaf8c 896void wxDivisionShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
0fc1a713
JS
897{
898 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
899 {
900 attachment = 0;
42cfaf8c 901 double dist;
0fc1a713
JS
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
42cfaf8c 912void wxDivisionShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
913{
914 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
915 {
916 attachment = 0;
42cfaf8c 917 double dist;
0fc1a713
JS
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
42cfaf8c 929void wxDivisionShape::OnEndDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
930{
931 m_canvas->ReleaseMouse();
932 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
933 {
934 attachment = 0;
42cfaf8c 935 double dist;
0fc1a713
JS
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
42cfaf8c 960void wxDivisionShape::SetSize(double w, double h, bool recursive)
0fc1a713
JS
961{
962 m_width = w;
963 m_height = h;
964 wxRectangleShape::SetSize(w, h, recursive);
965}
966
967void wxDivisionShape::CalculateSize()
968{
969}
970
2bb0cd28 971void wxDivisionShape::Copy(wxShape& copy)
0fc1a713
JS
972{
973 wxCompositeShape::Copy(copy);
974
2bb0cd28 975 wxASSERT( copy.IsKindOf(CLASSINFO(wxDivisionShape)) ) ;
0fc1a713 976
2bb0cd28 977 wxDivisionShape& divisionCopy = (wxDivisionShape&) copy;
0fc1a713 978
2bb0cd28
JS
979 divisionCopy.m_leftSideStyle = m_leftSideStyle;
980 divisionCopy.m_topSideStyle = m_topSideStyle;
981 divisionCopy.m_leftSideColour = m_leftSideColour;
982 divisionCopy.m_topSideColour = m_topSideColour;
0fc1a713 983
2bb0cd28
JS
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.
0fc1a713
JS
989}
990
991#ifdef PROLOGIO
992void 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
1012void 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
42cfaf8c 1025void wxDivisionShape::OnRightClick(double x, double y, int keys, int attachment)
0fc1a713
JS
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;
42cfaf8c 1049 double dist;
0fc1a713
JS
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
1061bool wxDivisionShape::Divide(int direction)
1062{
1063 // Calculate existing top-left, bottom-right
42cfaf8c
JS
1064 double x1 = (double)(GetX() - (GetWidth()/2.0));
1065 double y1 = (double)(GetY() - (GetHeight()/2.0));
0fc1a713 1066 wxCompositeShape *compositeParent = (wxCompositeShape *)GetParent();
42cfaf8c
JS
1067 double oldWidth = GetWidth();
1068 double oldHeight = GetHeight();
0fc1a713
JS
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.
42cfaf8c
JS
1079 double newXPos1 = GetX();
1080 double newYPos1 = (double)(y1 + (GetHeight()/4.0));
1081 double newXPos2 = GetX();
1082 double newYPos2 = (double)(y1 + (3.0*GetHeight()/4.0));
0fc1a713
JS
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
42cfaf8c 1120 SetSize(oldWidth, (double)(oldHeight/2.0));
0fc1a713
JS
1121 Move(dc, newXPos1, newYPos1);
1122
42cfaf8c 1123 newDivision->SetSize(oldWidth, (double)(oldHeight/2.0));
0fc1a713
JS
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.
42cfaf8c
JS
1130 double newXPos1 = (double)(x1 + (GetWidth()/4.0));
1131 double newYPos1 = GetY();
1132 double newXPos2 = (double)(x1 + (3.0*GetWidth()/4.0));
1133 double newYPos2 = GetY();
0fc1a713
JS
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
42cfaf8c 1161 SetSize((double)(oldWidth/2.0), oldHeight);
0fc1a713
JS
1162 Move(dc, newXPos1, newYPos1);
1163
42cfaf8c 1164 newDivision->SetSize((double)(oldWidth/2.0), oldHeight);
0fc1a713
JS
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
1178void wxDivisionShape::MakeControlPoints()
1179{
1180 MakeMandatoryControlPoints();
1181}
1182
1183void wxDivisionShape::MakeMandatoryControlPoints()
1184{
42cfaf8c 1185 double maxX, maxY;
0fc1a713
JS
1186
1187 GetBoundingBoxMax(&maxX, &maxY);
42cfaf8c 1188 double x, y;
0fc1a713
JS
1189 int direction;
1190/*
1191 if (m_leftSide)
1192 {
42cfaf8c 1193 x = (double)(-maxX/2.0);
0fc1a713
JS
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;
42cfaf8c 1203 y = (double)(-maxY/2.0);
0fc1a713
JS
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 {
42cfaf8c 1214 x = (double)(-maxX/2.0);
0fc1a713
JS
1215 y = 0.0;
1216 direction = CONTROL_POINT_HORIZONTAL;
1217 break;
1218 }
1219 case DIVISION_SIDE_TOP:
1220 {
1221 x = 0.0;
42cfaf8c 1222 y = (double)(-maxY/2.0);
0fc1a713
JS
1223 direction = CONTROL_POINT_VERTICAL;
1224 break;
1225 }
1226 case DIVISION_SIDE_RIGHT:
1227 {
42cfaf8c 1228 x = (double)(maxX/2.0);
0fc1a713
JS
1229 y = 0.0;
1230 direction = CONTROL_POINT_HORIZONTAL;
1231 break;
1232 }
1233 case DIVISION_SIDE_BOTTOM:
1234 {
1235 x = 0.0;
42cfaf8c 1236 y = (double)(maxY/2.0);
0fc1a713
JS
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
1252void wxDivisionShape::ResetControlPoints()
1253{
1254 ResetMandatoryControlPoints();
1255}
1256
1257void wxDivisionShape::ResetMandatoryControlPoints()
1258{
1259 if (m_controlPoints.Number() < 1)
1260 return;
1261
42cfaf8c 1262 double maxX, maxY;
0fc1a713
JS
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 {
42cfaf8c 1272 control->xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
0fc1a713
JS
1273 }
1274 else if (control->type == CONTROL_POINT_VERTICAL)
1275 {
42cfaf8c 1276 control->xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
0fc1a713
JS
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();
42cfaf8c 1285 control->m_xoffset = (double)(-maxX/2.0); control->m_yoffset = 0.0;
0fc1a713
JS
1286 }
1287
1288 if ((m_handleSide == DIVISION_SIDE_TOP) && node)
1289 {
1290 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data();
42cfaf8c 1291 control->m_xoffset = 0.0; control->m_yoffset = (double)(-maxY/2.0);
0fc1a713
JS
1292 }
1293
1294 if ((m_handleSide == DIVISION_SIDE_RIGHT) && node)
1295 {
1296 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data();
42cfaf8c 1297 control->m_xoffset = (double)(maxX/2.0); control->m_yoffset = 0.0;
0fc1a713
JS
1298 }
1299
1300 if ((m_handleSide == DIVISION_SIDE_BOTTOM) && node)
1301 {
1302 wxDivisionControlPoint *control = (wxDivisionControlPoint *)node->Data();
42cfaf8c 1303 control->m_xoffset = 0.0; control->m_yoffset = (double)(maxY/2.0);
0fc1a713
JS
1304 }
1305}
1306
1307// Adjust a side, returning FALSE if it's not physically possible.
42cfaf8c 1308bool wxDivisionShape::AdjustLeft(double left, bool test)
0fc1a713 1309{
42cfaf8c 1310 double x2 = (double)(GetX() + (GetWidth()/2.0));
0fc1a713
JS
1311
1312 if (left >= x2)
1313 return FALSE;
1314 if (test)
1315 return TRUE;
1316
42cfaf8c
JS
1317 double newW = x2 - left;
1318 double newX = (double)(left + newW/2.0);
0fc1a713
JS
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
42cfaf8c 1329bool wxDivisionShape::AdjustTop(double top, bool test)
0fc1a713 1330{
42cfaf8c 1331 double y2 = (double)(GetY() + (GetHeight()/2.0));
0fc1a713
JS
1332
1333 if (top >= y2)
1334 return FALSE;
1335 if (test)
1336 return TRUE;
1337
42cfaf8c
JS
1338 double newH = y2 - top;
1339 double newY = (double)(top + newH/2.0);
0fc1a713
JS
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
42cfaf8c 1350bool wxDivisionShape::AdjustRight(double right, bool test)
0fc1a713 1351{
42cfaf8c 1352 double x1 = (double)(GetX() - (GetWidth()/2.0));
0fc1a713
JS
1353
1354 if (right <= x1)
1355 return FALSE;
1356 if (test)
1357 return TRUE;
1358
42cfaf8c
JS
1359 double newW = right - x1;
1360 double newX = (double)(x1 + newW/2.0);
0fc1a713
JS
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
42cfaf8c 1371bool wxDivisionShape::AdjustBottom(double bottom, bool test)
0fc1a713 1372{
42cfaf8c 1373 double y1 = (double)(GetY() - (GetHeight()/2.0));
0fc1a713
JS
1374
1375 if (bottom <= y1)
1376 return FALSE;
1377 if (test)
1378 return TRUE;
1379
42cfaf8c
JS
1380 double newH = bottom - y1;
1381 double newY = (double)(y1 + newH/2.0);
0fc1a713
JS
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
42cfaf8c 1392wxDivisionControlPoint::wxDivisionControlPoint(wxShapeCanvas *the_canvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type):
0fc1a713
JS
1393 wxControlPoint(the_canvas, object, size, the_xoffset, the_yoffset, the_type)
1394{
1395 SetEraseObject(FALSE);
1396}
1397
1398wxDivisionControlPoint::~wxDivisionControlPoint()
1399{
1400}
1401
42cfaf8c
JS
1402static double originalX = 0.0;
1403static double originalY = 0.0;
1404static double originalW = 0.0;
1405static double originalH = 0.0;
0fc1a713
JS
1406
1407// Implement resizing of canvas object
42cfaf8c 1408void wxDivisionControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
0fc1a713
JS
1409{
1410 wxControlPoint::OnDragLeft(draw, x, y, keys, attachment);
1411}
1412
42cfaf8c 1413void wxDivisionControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
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
42cfaf8c 1424void wxDivisionControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
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.
42cfaf8c
JS
1435 double x1 = (double)(divisionParent->GetX() - (divisionParent->GetWidth()/2.0));
1436 double y1 = (double)(divisionParent->GetY() - (divisionParent->GetHeight()/2.0));
1437 double x2 = (double)(divisionParent->GetX() + (divisionParent->GetWidth()/2.0));
1438 double y2 = (double)(divisionParent->GetY() + (divisionParent->GetHeight()/2.0));
0fc1a713
JS
1439
1440 // Need to check it has not made the division zero or negative width/height
42cfaf8c
JS
1441 double dx1 = (double)(division->GetX() - (division->GetWidth()/2.0));
1442 double dy1 = (double)(division->GetY() - (division->GetHeight()/2.0));
1443 double dx2 = (double)(division->GetX() + (division->GetWidth()/2.0));
1444 double dy2 = (double)(division->GetY() + (division->GetHeight()/2.0));
0fc1a713
JS
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 */
42cfaf8c 1515bool wxDivisionShape::ResizeAdjoining(int side, double newPos, bool test)
0fc1a713
JS
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
1578void 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
1608void 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
42cfaf8c 1717void wxDivisionShape::PopupMenu(double x, double y)
0fc1a713
JS
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
1744void wxDivisionShape::SetLeftSideColour(const wxString& colour)
1745{
1746 m_leftSideColour = colour;
1747}
1748
1749void wxDivisionShape::SetTopSideColour(const wxString& colour)
1750{
1751 m_topSideColour = colour;
1752}
1753
1754void wxDivisionShape::SetLeftSideStyle(const wxString& style)
1755{
1756 m_leftSideStyle = style;
1757}
1758
1759void wxDivisionShape::SetTopSideStyle(const wxString& style)
1760{
1761 m_topSideStyle = style;
1762}
1763