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