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