]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/ogl/divided.cpp
updates from Adrián González Alba
[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 // 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
30 class 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
46 IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint, wxControlPoint)
47
48 /*
49 * Divided object
50 *
51 */
52
53 IMPLEMENT_DYNAMIC_CLASS(wxDividedShape, wxRectangleShape)
54
55 wxDividedShape::wxDividedShape(double w, double h): wxRectangleShape(w, h)
56 {
57 ClearRegions();
58 }
59
60 wxDividedShape::~wxDividedShape()
61 {
62 }
63
64 void wxDividedShape::OnDraw(wxDC& dc)
65 {
66 wxRectangleShape::OnDraw(dc);
67 }
68
69 void 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
136 void 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
144 void 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
177 bool 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
290 int 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
308 bool 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
321 void wxDividedShape::Copy(wxShape& copy)
322 {
323 wxRectangleShape::Copy(copy);
324 }
325
326 // Region operations
327
328 void wxDividedShape::MakeControlPoints()
329 {
330 wxRectangleShape::MakeControlPoints();
331
332 MakeMandatoryControlPoints();
333 }
334
335 void 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
364 void 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
373 void 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
403 void wxDividedShape::WriteAttributes(wxExpr *clause)
404 {
405 wxRectangleShape::WriteAttributes(clause);
406 }
407
408 void wxDividedShape::ReadAttributes(wxExpr *clause)
409 {
410 wxRectangleShape::ReadAttributes(clause);
411 }
412 #endif
413
414 /*
415 * Edit the division colour/style
416 *
417 */
418
419 void 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
554 void 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
566 wxDividedShapeControlPoint::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
573 wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
574 {
575 }
576
577 // Implement resizing of divided object division
578 void 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
596 void 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
615 void 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