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