]> git.saurik.com Git - wxWidgets.git/blame_incremental - contrib/src/ogl/divided.cpp
Needed to add #include "wx/statusbr.h" to know that wxStatusBar is derived
[wxWidgets.git] / contrib / src / ogl / divided.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: divided.cpp
3// Purpose: wxDividedShape 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// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16#pragma hdrstop
17#endif
18
19#ifndef WX_PRECOMP
20#include <wx/wx.h>
21#endif
22
23#if wxUSE_PROLOGIO
24#include <wx/deprecated/wxexpr.h>
25#endif
26
27#include "wx/ogl/ogl.h"
28
29
30class wxDividedShapeControlPoint: public wxControlPoint
31{
32 DECLARE_DYNAMIC_CLASS(wxDividedShapeControlPoint)
33 private:
34 int regionId;
35 public:
36 wxDividedShapeControlPoint() { regionId = 0; }
37 wxDividedShapeControlPoint(wxShapeCanvas *the_canvas, wxShape *object, int region,
38 double size, double the_xoffset, double the_yoffset, int the_type);
39 ~wxDividedShapeControlPoint();
40
41 void OnDragLeft(bool draw, double x, double y, int keys=0, int attachment = 0);
42 void OnBeginDragLeft(double x, double y, int keys=0, int attachment = 0);
43 void OnEndDragLeft(double x, double y, int keys=0, int attachment = 0);
44};
45
46IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint, wxControlPoint)
47
48/*
49 * Divided object
50 *
51 */
52
53IMPLEMENT_DYNAMIC_CLASS(wxDividedShape, wxRectangleShape)
54
55wxDividedShape::wxDividedShape(double w, double h): wxRectangleShape(w, h)
56{
57 ClearRegions();
58}
59
60wxDividedShape::~wxDividedShape()
61{
62}
63
64void wxDividedShape::OnDraw(wxDC& dc)
65{
66 wxRectangleShape::OnDraw(dc);
67}
68
69void wxDividedShape::OnDrawContents(wxDC& dc)
70{
71 double defaultProportion = (double)(GetRegions().GetCount() > 0 ? (1.0/((double)(GetRegions().GetCount()))) : 0.0);
72 double currentY = (double)(m_ypos - (m_height / 2.0));
73 double maxY = (double)(m_ypos + (m_height / 2.0));
74
75 double leftX = (double)(m_xpos - (m_width / 2.0));
76 double rightX = (double)(m_xpos + (m_width / 2.0));
77
78 if (m_pen) dc.SetPen(* m_pen);
79
80 dc.SetTextForeground(m_textColour);
81
82#ifdef __WXMSW__
83 // For efficiency, don't do this under X - doesn't make
84 // any visible difference for our purposes.
85 if (m_brush)
86 dc.SetTextBackground(m_brush->GetColour());
87#endif
88/*
89 if (!formatted)
90 {
91 FormatRegionText();
92 formatted = true;
93 }
94*/
95 if (GetDisableLabel()) return;
96
97 double xMargin = 2;
98 double yMargin = 2;
99 dc.SetBackgroundMode(wxTRANSPARENT);
100
101 wxObjectList::compatibility_iterator node = GetRegions().GetFirst();
102 while (node)
103 {
104 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
105 dc.SetFont(* region->GetFont());
106 dc.SetTextForeground(region->GetActualColourObject());
107
108 double proportion =
109 region->m_regionProportionY < 0.0 ? defaultProportion : region->m_regionProportionY;
110
111 double y = currentY + m_height*proportion;
112 double actualY = maxY < y ? maxY : y;
113
114 double centreX = m_xpos;
115 double centreY = (double)(currentY + (actualY - currentY)/2.0);
116
117 oglDrawFormattedText(dc, &region->m_formattedText,
118 (double)(centreX), (double)(centreY), (double)(m_width-2*xMargin), (double)(actualY - currentY - 2*yMargin),
119 region->m_formatMode);
120 if ((y <= maxY) && (node->GetNext()))
121 {
122 wxPen *regionPen = region->GetActualPen();
123 if (regionPen)
124 {
125 dc.SetPen(* regionPen);
126 dc.DrawLine(WXROUND(leftX), WXROUND(y), WXROUND(rightX), WXROUND(y));
127 }
128 }
129
130 currentY = actualY;
131
132 node = node->GetNext();
133 }
134}
135
136void wxDividedShape::SetSize(double w, double h, bool WXUNUSED(recursive))
137{
138 SetAttachmentSize(w, h);
139 m_width = w;
140 m_height = h;
141 SetRegionSizes();
142}
143
144void wxDividedShape::SetRegionSizes()
145{
146 if (GetRegions().GetCount() == 0)
147 return;
148
149 double defaultProportion = (double)(GetRegions().GetCount() > 0 ? (1.0/((double)(GetRegions().GetCount()))) : 0.0);
150 double currentY = (double)(m_ypos - (m_height / 2.0));
151 double maxY = (double)(m_ypos + (m_height / 2.0));
152
153// double leftX = (double)(m_xpos - (m_width / 2.0));
154// double rightX = (double)(m_xpos + (m_width / 2.0));
155
156 wxObjectList::compatibility_iterator node = GetRegions().GetFirst();
157 while (node)
158 {
159 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
160 double proportion =
161 region->m_regionProportionY <= 0.0 ? defaultProportion : region->m_regionProportionY;
162
163 double sizeY = (double)proportion*m_height;
164 double y = currentY + sizeY;
165 double actualY = maxY < y ? maxY : y;
166
167 double centreY = (double)(currentY + (actualY - currentY)/2.0);
168
169 region->SetSize(m_width, sizeY);
170 region->SetPosition(0.0, (double)(centreY - m_ypos));
171 currentY = actualY;
172 node = node->GetNext();
173 }
174}
175
176// Attachment points correspond to regions in the divided box
177bool wxDividedShape::GetAttachmentPosition(int attachment, double *x, double *y, int nth, int no_arcs,
178 wxLineShape *line)
179{
180 int totalNumberAttachments = (GetRegions().GetCount() * 2) + 2;
181 if ((GetAttachmentMode() == ATTACHMENT_MODE_NONE) || (attachment >= totalNumberAttachments))
182 {
183 return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs);
184 }
185
186 int n = GetRegions().GetCount();
187 bool isEnd = (line && line->IsEnd(this));
188
189 double left = (double)(m_xpos - m_width/2.0);
190 double right = (double)(m_xpos + m_width/2.0);
191 double top = (double)(m_ypos - m_height/2.0);
192 double bottom = (double)(m_ypos + m_height/2.0);
193
194 // Zero is top, n+1 is bottom.
195 if (attachment == 0)
196 {
197 *y = top;
198 if (m_spaceAttachments)
199 {
200 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
201 {
202 // Align line according to the next handle along
203 wxRealPoint *point = line->GetNextControlPoint(this);
204 if (point->x < left)
205 *x = left;
206 else if (point->x > right)
207 *x = right;
208 else
209 *x = point->x;
210 }
211 else
212 *x = left + (nth + 1)*m_width/(no_arcs + 1);
213 }
214 else
215 *x = m_xpos;
216 }
217 else if (attachment == (n+1))
218 {
219 *y = bottom;
220 if (m_spaceAttachments)
221 {
222 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
223 {
224 // Align line according to the next handle along
225 wxRealPoint *point = line->GetNextControlPoint(this);
226 if (point->x < left)
227 *x = left;
228 else if (point->x > right)
229 *x = right;
230 else
231 *x = point->x;
232 }
233 else
234 *x = left + (nth + 1)*m_width/(no_arcs + 1);
235 }
236 else
237 *x = m_xpos;
238 }
239 // Left or right.
240 else
241 {
242 bool isLeft = !(attachment < (n+1));
243 int i = (isLeft) ? (totalNumberAttachments - attachment - 1) : (attachment-1);
244 wxObjectList::compatibility_iterator node = GetRegions().Item(i);
245 if (node)
246 {
247 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
248
249 if (isLeft)
250 *x = left;
251 else
252 *x = right;
253
254 // Calculate top and bottom of region
255 top = (double)((m_ypos + region->m_y) - (region->m_height/2.0));
256 bottom = (double)((m_ypos + region->m_y) + (region->m_height/2.0));
257
258 // Assuming we can trust the absolute size and
259 // position of these regions...
260 if (m_spaceAttachments)
261 {
262 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
263 {
264 // Align line according to the next handle along
265 wxRealPoint *point = line->GetNextControlPoint(this);
266 if (point->y < bottom)
267 *y = bottom;
268 else if (point->y > top)
269 *y = top;
270 else
271 *y = point->y;
272 }
273 else
274// *y = (double)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1));
275 *y = (double)(top + (nth + 1)*region->m_height/(no_arcs+1));
276 }
277 else
278 *y = (double)(m_ypos + region->m_y);
279 }
280 else
281 {
282 *x = m_xpos;
283 *y = m_ypos;
284 return false;
285 }
286 }
287 return true;
288}
289
290int wxDividedShape::GetNumberOfAttachments() const
291{
292 // There are two attachments for each region (left and right),
293 // plus one on the top and one on the bottom.
294 int n = (GetRegions().GetCount() * 2) + 2;
295
296 int maxN = n - 1;
297 wxObjectList::compatibility_iterator node = m_attachmentPoints.GetFirst();
298 while (node)
299 {
300 wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
301 if (point->m_id > maxN)
302 maxN = point->m_id;
303 node = node->GetNext();
304 }
305 return maxN + 1;
306}
307
308bool wxDividedShape::AttachmentIsValid(int attachment) const
309{
310 int totalNumberAttachments = (GetRegions().GetCount() * 2) + 2;
311 if (attachment >= totalNumberAttachments)
312 {
313 return wxShape::AttachmentIsValid(attachment);
314 }
315 else if (attachment >= 0)
316 return true;
317 else
318 return false;
319}
320
321void wxDividedShape::Copy(wxShape& copy)
322{
323 wxRectangleShape::Copy(copy);
324}
325
326// Region operations
327
328void wxDividedShape::MakeControlPoints()
329{
330 wxRectangleShape::MakeControlPoints();
331
332 MakeMandatoryControlPoints();
333}
334
335void wxDividedShape::MakeMandatoryControlPoints()
336{
337 double currentY = (double)(GetY() - (m_height / 2.0));
338 double maxY = (double)(GetY() + (m_height / 2.0));
339
340 wxObjectList::compatibility_iterator node = GetRegions().GetFirst();
341 int i = 0;
342 while (node)
343 {
344 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
345
346 double proportion = region->m_regionProportionY;
347
348 double y = currentY + m_height*proportion;
349 double actualY = (double)(maxY < y ? maxY : y);
350
351 if (node->GetNext())
352 {
353 wxDividedShapeControlPoint *controlPoint =
354 new wxDividedShapeControlPoint(m_canvas, this, i, CONTROL_POINT_SIZE, 0.0, (double)(actualY - GetY()), 0);
355 m_canvas->AddShape(controlPoint);
356 m_controlPoints.Append(controlPoint);
357 }
358 currentY = actualY;
359 i ++;
360 node = node->GetNext();
361 }
362}
363
364void wxDividedShape::ResetControlPoints()
365{
366 // May only have the region handles, (n - 1) of them.
367 if (m_controlPoints.GetCount() > (GetRegions().GetCount() - 1))
368 wxRectangleShape::ResetControlPoints();
369
370 ResetMandatoryControlPoints();
371}
372
373void wxDividedShape::ResetMandatoryControlPoints()
374{
375 double currentY = (double)(GetY() - (m_height / 2.0));
376 double maxY = (double)(GetY() + (m_height / 2.0));
377
378 wxObjectList::compatibility_iterator node = m_controlPoints.GetFirst();
379 int i = 0;
380 while (node)
381 {
382 wxControlPoint *controlPoint = (wxControlPoint *)node->GetData();
383 if (controlPoint->IsKindOf(CLASSINFO(wxDividedShapeControlPoint)))
384 {
385 wxObjectList::compatibility_iterator node1 = GetRegions().Item(i);
386 wxShapeRegion *region = (wxShapeRegion *)node1->GetData();
387
388 double proportion = region->m_regionProportionY;
389
390 double y = currentY + m_height*proportion;
391 double actualY = (double)(maxY < y ? maxY : y);
392
393 controlPoint->m_xoffset = 0.0;
394 controlPoint->m_yoffset = (double)(actualY - GetY());
395 currentY = actualY;
396 i ++;
397 }
398 node = node->GetNext();
399 }
400}
401
402#if wxUSE_PROLOGIO
403void wxDividedShape::WriteAttributes(wxExpr *clause)
404{
405 wxRectangleShape::WriteAttributes(clause);
406}
407
408void wxDividedShape::ReadAttributes(wxExpr *clause)
409{
410 wxRectangleShape::ReadAttributes(clause);
411}
412#endif
413
414/*
415 * Edit the division colour/style
416 *
417 */
418
419void wxDividedShape::EditRegions()
420{
421 wxMessageBox(wxT("EditRegions() is unimplemented."), wxT("OGL"), wxOK);
422
423 // TODO
424#if 0
425 if (GetRegions().GetCount() < 2)
426 return;
427
428 wxBeginBusyCursor();
429
430 GraphicsForm *form = new GraphicsForm("Divided nodes");
431 // Need an array to store all the style strings,
432 // since they need to be converted to integers
433 char **styleStrings = new char *[GetRegions().GetCount()];
434 for (int j = 0; j < GetRegions().GetCount(); j++)
435 styleStrings[j] = NULL;
436
437 int i = 0;
438 wxNode *node = GetRegions().GetFirst();
439 while (node && node->GetNext())
440 {
441 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
442 char buf[50];
443 sprintf(buf, "Region %d", (i+1));
444 form->Add(wxMakeFormMessage(buf));
445 form->Add(wxMakeFormNewLine());
446
447 form->Add(wxMakeFormString("Colour", &region->penColour, wxFORM_CHOICE,
448 new wxList(wxMakeConstraintStrings(
449 "Invisible" ,
450 "BLACK" ,
451 "BLUE" ,
452 "BROWN" ,
453 "CORAL" ,
454 "CYAN" ,
455 "DARK GREY" ,
456 "DARK GREEN" ,
457 "DIM GREY" ,
458 "GREY" ,
459 "GREEN" ,
460 "LIGHT BLUE" ,
461 "LIGHT GREY" ,
462 "MAGENTA" ,
463 "MAROON" ,
464 "NAVY" ,
465 "ORANGE" ,
466 "PURPLE" ,
467 "RED" ,
468 "TURQUOISE" ,
469 "VIOLET" ,
470 "WHITE" ,
471 "YELLOW" ,
472 NULL),
473 NULL), NULL, wxVERTICAL, 150));
474
475 char *styleString = NULL;
476 switch (region->penStyle)
477 {
478 case wxSHORT_DASH:
479 styleString = "Short Dash";
480 break;
481 case wxLONG_DASH:
482 styleString = "Long Dash";
483 break;
484 case wxDOT:
485 styleString = "Dot";
486 break;
487 case wxDOT_DASH:
488 styleString = "Dot Dash";
489 break;
490 case wxSOLID:
491 default:
492 styleString = "Solid";
493 break;
494 }
495 styleStrings[i] = copystring(styleString);
496 form->Add(wxMakeFormString("Style", &(styleStrings[i]), wxFORM_CHOICE,
497 new wxList(wxMakeConstraintStrings(
498 "Solid" ,
499 "Short Dash" ,
500 "Long Dash" ,
501 "Dot" ,
502 "Dot Dash" ,
503 NULL),
504 NULL), NULL, wxVERTICAL, 100));
505 node = node->GetNext();
506 i ++;
507 if (node && node->GetNext())
508 form->Add(wxMakeFormNewLine());
509 }
510 wxDialogBox *dialog = new wxDialogBox(m_canvas->GetParent(), "Divided object properties", 10, 10, 500, 500);
511 if (GraphicsLabelFont)
512 dialog->SetLabelFont(GraphicsLabelFont);
513 if (GraphicsButtonFont)
514 dialog->SetButtonFont(GraphicsButtonFont);
515 form->AssociatePanel(dialog);
516 form->dialog = dialog;
517
518 dialog->Fit();
519 dialog->Centre(wxBOTH);
520
521 wxEndBusyCursor();
522
523 dialog->Show(true);
524
525 node = GetRegions().GetFirst();
526 i = 0;
527 while (node)
528 {
529 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
530
531 if (styleStrings[i])
532 {
533 if (strcmp(styleStrings[i], "Solid") == 0)
534 region->penStyle = wxSOLID;
535 else if (strcmp(styleStrings[i], "Dot") == 0)
536 region->penStyle = wxDOT;
537 else if (strcmp(styleStrings[i], "Short Dash") == 0)
538 region->penStyle = wxSHORT_DASH;
539 else if (strcmp(styleStrings[i], "Long Dash") == 0)
540 region->penStyle = wxLONG_DASH;
541 else if (strcmp(styleStrings[i], "Dot Dash") == 0)
542 region->penStyle = wxDOT_DASH;
543 delete[] styleStrings[i];
544 }
545 region->m_actualPenObject = NULL;
546 node = node->GetNext();
547 i ++;
548 }
549 delete[] styleStrings;
550 Draw(dc);
551#endif
552}
553
554void wxDividedShape::OnRightClick(double x, double y, int keys, int attachment)
555{
556 if (keys & KEY_CTRL)
557 {
558 EditRegions();
559 }
560 else
561 {
562 wxRectangleShape::OnRightClick(x, y, keys, attachment);
563 }
564}
565
566wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas *the_canvas, wxShape *object,
567 int region, double size, double the_m_xoffset, double the_m_yoffset, int the_type):
568 wxControlPoint(the_canvas, object, size, the_m_xoffset, the_m_yoffset, the_type)
569{
570 regionId = region;
571}
572
573wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
574{
575}
576
577// Implement resizing of divided object division
578void wxDividedShapeControlPoint::OnDragLeft(bool WXUNUSED(draw), double WXUNUSED(x), double y, int WXUNUSED(keys), int WXUNUSED(attachment))
579{
580 wxClientDC dc(GetCanvas());
581 GetCanvas()->PrepareDC(dc);
582
583 dc.SetLogicalFunction(OGLRBLF);
584 wxPen dottedPen(*wxBLACK, 1, wxDOT);
585 dc.SetPen(dottedPen);
586 dc.SetBrush((* wxTRANSPARENT_BRUSH));
587
588 wxDividedShape *dividedObject = (wxDividedShape *)m_shape;
589 double x1 = (double)(dividedObject->GetX() - (dividedObject->GetWidth()/2.0));
590 double y1 = y;
591 double x2 = (double)(dividedObject->GetX() + (dividedObject->GetWidth()/2.0));
592 double y2 = y;
593 dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y2));
594}
595
596void wxDividedShapeControlPoint::OnBeginDragLeft(double WXUNUSED(x), double y, int WXUNUSED(keys), int WXUNUSED(attachment))
597{
598 wxClientDC dc(GetCanvas());
599 GetCanvas()->PrepareDC(dc);
600
601 wxDividedShape *dividedObject = (wxDividedShape *)m_shape;
602 dc.SetLogicalFunction(OGLRBLF);
603 wxPen dottedPen(*wxBLACK, 1, wxDOT);
604 dc.SetPen(dottedPen);
605 dc.SetBrush((* wxTRANSPARENT_BRUSH));
606
607 double x1 = (double)(dividedObject->GetX() - (dividedObject->GetWidth()/2.0));
608 double y1 = y;
609 double x2 = (double)(dividedObject->GetX() + (dividedObject->GetWidth()/2.0));
610 double y2 = y;
611 dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y2));
612 m_canvas->CaptureMouse();
613}
614
615void wxDividedShapeControlPoint::OnEndDragLeft(double WXUNUSED(x), double y, int WXUNUSED(keys), int WXUNUSED(attachment))
616{
617 wxClientDC dc(GetCanvas());
618 GetCanvas()->PrepareDC(dc);
619
620 wxDividedShape *dividedObject = (wxDividedShape *)m_shape;
621 wxObjectList::compatibility_iterator node = dividedObject->GetRegions().Item(regionId);
622 if (!node)
623 return;
624
625 wxShapeRegion *thisRegion = (wxShapeRegion *)node->GetData();
626 wxShapeRegion *nextRegion = NULL; // Region below this one
627
628 dc.SetLogicalFunction(wxCOPY);
629
630 m_canvas->ReleaseMouse();
631
632 // Find the old top and bottom of this region,
633 // and calculate the new proportion for this region
634 // if legal.
635
636 double currentY = (double)(dividedObject->GetY() - (dividedObject->GetHeight() / 2.0));
637 double maxY = (double)(dividedObject->GetY() + (dividedObject->GetHeight() / 2.0));
638
639 // Save values
640 double thisRegionTop = 0.0;
641 double nextRegionBottom = 0.0;
642
643 node = dividedObject->GetRegions().GetFirst();
644 while (node)
645 {
646 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
647
648 double proportion = region->m_regionProportionY;
649 double yy = currentY + (dividedObject->GetHeight()*proportion);
650 double actualY = (double)(maxY < yy ? maxY : yy);
651
652 if (region == thisRegion)
653 {
654 thisRegionTop = currentY;
655 if (node->GetNext())
656 nextRegion = (wxShapeRegion *)node->GetNext()->GetData();
657 }
658 if (region == nextRegion)
659 {
660 nextRegionBottom = actualY;
661 }
662
663 currentY = actualY;
664 node = node->GetNext();
665 }
666 if (!nextRegion)
667 return;
668
669 // Check that we haven't gone above this region or below
670 // next region.
671 if ((y <= thisRegionTop) || (y >= nextRegionBottom))
672 return;
673
674 dividedObject->EraseLinks(dc);
675
676 // Now calculate the new proportions of this region and the next region.
677 double thisProportion = (double)((y - thisRegionTop)/dividedObject->GetHeight());
678 double nextProportion = (double)((nextRegionBottom - y)/dividedObject->GetHeight());
679 thisRegion->SetProportions(0.0, thisProportion);
680 nextRegion->SetProportions(0.0, nextProportion);
681 m_yoffset = (double)(y - dividedObject->GetY());
682
683 // Now reformat text
684 int i = 0;
685 node = dividedObject->GetRegions().GetFirst();
686 while (node)
687 {
688 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
689 if (region->GetText())
690 {
691 wxString s(region->GetText());
692 dividedObject->FormatText(dc, s.c_str(), i);
693 }
694 node = node->GetNext();
695 i++;
696 }
697 dividedObject->SetRegionSizes();
698 dividedObject->Draw(dc);
699 dividedObject->GetEventHandler()->OnMoveLinks(dc);
700}
701