1
//////////////////////////////////////////////////////////////////////////
3
// pgAdmin III - PostgreSQL Tools
5
// Portions Copyright (C) 1998 - 2011, Julian Smart
6
// Portions Copyright (C) 2011, The pgAdmin Development Team
7
// This software is released under the PostgreSQL Licence
9
// divided.cpp - wxDividedShape class
11
//////////////////////////////////////////////////////////////////////////
18
oglCopystring (const wxChar *s)
20
if (s == NULL) s = wxEmptyString;
21
size_t len = wxStrlen (s) + 1;
23
wxChar *news = new wxChar[len];
24
memcpy (news, s, len * sizeof(wxChar)); // Should be the fastest
29
class wxDividedShapeControlPoint: public wxControlPoint
31
DECLARE_DYNAMIC_CLASS(wxDividedShapeControlPoint)
35
wxDividedShapeControlPoint()
39
wxDividedShapeControlPoint(wxShapeCanvas *the_canvas, wxShape *object, int region,
40
double size, double the_xoffset, double the_yoffset, int the_type);
41
~wxDividedShapeControlPoint();
43
void OnDragLeft(bool draw, double x, double y, int keys = 0, int attachment = 0);
44
void OnBeginDragLeft(double x, double y, int keys = 0, int attachment = 0);
45
void OnEndDragLeft(double x, double y, int keys = 0, int attachment = 0);
48
IMPLEMENT_DYNAMIC_CLASS(wxDividedShapeControlPoint, wxControlPoint)
55
IMPLEMENT_DYNAMIC_CLASS(wxDividedShape, wxRectangleShape)
57
wxDividedShape::wxDividedShape(double w, double h): wxRectangleShape(w, h)
62
wxDividedShape::~wxDividedShape()
66
void wxDividedShape::OnDraw(wxDC &dc)
68
wxRectangleShape::OnDraw(dc);
71
void wxDividedShape::OnDrawContents(wxDC &dc)
73
double defaultProportion = (double)(GetRegions().GetCount() > 0 ? (1.0 / ((double)(GetRegions().GetCount()))) : 0.0);
74
double currentY = (double)(m_ypos - (m_height / 2.0));
75
double maxY = (double)(m_ypos + (m_height / 2.0));
77
double leftX = (double)(m_xpos - (m_width / 2.0));
78
double rightX = (double)(m_xpos + (m_width / 2.0));
80
if (m_pen) dc.SetPen(* m_pen);
82
if (m_textColour.IsOk()) dc.SetTextForeground(m_textColour);
85
// For efficiency, don't do this under X - doesn't make
86
// any visible difference for our purposes.
88
dc.SetTextBackground(m_brush->GetColour());
97
if (GetDisableLabel()) return;
101
dc.SetBackgroundMode(wxTRANSPARENT);
103
wxNode *node = GetRegions().GetFirst();
106
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
107
dc.SetFont(* region->GetFont());
108
dc.SetTextForeground(region->GetActualColourObject());
111
region->m_regionProportionY < 0.0 ? defaultProportion : region->m_regionProportionY;
113
double y = currentY + m_height * proportion;
114
double actualY = maxY < y ? maxY : y;
116
double centreX = m_xpos;
117
double centreY = (double)(currentY + (actualY - currentY) / 2.0);
119
oglDrawFormattedText(dc, ®ion->m_formattedText,
120
(double)(centreX), (double)(centreY), (double)(m_width - 2 * xMargin), (double)(actualY - currentY - 2 * yMargin),
121
region->m_formatMode);
122
if ((y <= maxY) && (node->GetNext()))
124
wxPen *regionPen = region->GetActualPen();
127
dc.SetPen(* regionPen);
128
dc.DrawLine(WXROUND(leftX), WXROUND(y), WXROUND(rightX), WXROUND(y));
134
node = node->GetNext();
138
void wxDividedShape::SetSize(double w, double h, bool WXUNUSED(recursive))
140
SetAttachmentSize(w, h);
146
void wxDividedShape::SetRegionSizes()
148
if (GetRegions().GetCount() == 0)
151
double defaultProportion = (double)(GetRegions().GetCount() > 0 ? (1.0 / ((double)(GetRegions().GetCount()))) : 0.0);
152
double currentY = (double)(m_ypos - (m_height / 2.0));
153
double maxY = (double)(m_ypos + (m_height / 2.0));
155
// double leftX = (double)(m_xpos - (m_width / 2.0));
156
// double rightX = (double)(m_xpos + (m_width / 2.0));
158
wxNode *node = GetRegions().GetFirst();
161
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
163
region->m_regionProportionY <= 0.0 ? defaultProportion : region->m_regionProportionY;
165
double sizeY = (double)proportion * m_height;
166
double y = currentY + sizeY;
167
double actualY = maxY < y ? maxY : y;
169
double centreY = (double)(currentY + (actualY - currentY) / 2.0);
171
region->SetSize(m_width, sizeY);
172
region->SetPosition(0.0, (double)(centreY - m_ypos));
174
node = node->GetNext();
178
// Attachment points correspond to regions in the divided box
179
bool wxDividedShape::GetAttachmentPosition(int attachment, double *x, double *y, int nth, int no_arcs,
182
int totalNumberAttachments = (GetRegions().GetCount() * 2) + 2;
183
if ((GetAttachmentMode() == ATTACHMENT_MODE_NONE) || (attachment >= totalNumberAttachments))
185
return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs);
188
int n = GetRegions().GetCount();
189
bool isEnd = (line && line->IsEnd(this));
191
double left = (double)(m_xpos - m_width / 2.0);
192
double right = (double)(m_xpos + m_width / 2.0);
193
double top = (double)(m_ypos - m_height / 2.0);
194
double bottom = (double)(m_ypos + m_height / 2.0);
196
// Zero is top, n+1 is bottom.
200
if (m_spaceAttachments)
202
if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
204
// Align line according to the next handle along
205
wxRealPoint *point = line->GetNextControlPoint(this);
208
else if (point->x > right)
214
*x = left + (nth + 1) * m_width / (no_arcs + 1);
219
else if (attachment == (n + 1))
222
if (m_spaceAttachments)
224
if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
226
// Align line according to the next handle along
227
wxRealPoint *point = line->GetNextControlPoint(this);
230
else if (point->x > right)
236
*x = left + (nth + 1) * m_width / (no_arcs + 1);
244
bool isLeft = !(attachment < (n + 1));
245
int i = (isLeft) ? (totalNumberAttachments - attachment - 1) : (attachment - 1);
246
wxNode *node = GetRegions().Item(i);
249
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
256
// Calculate top and bottom of region
257
top = (double)((m_ypos + region->m_y) - (region->m_height / 2.0));
258
bottom = (double)((m_ypos + region->m_y) + (region->m_height / 2.0));
260
// Assuming we can trust the absolute size and
261
// position of these regions...
262
if (m_spaceAttachments)
264
if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
266
// Align line according to the next handle along
267
wxRealPoint *point = line->GetNextControlPoint(this);
268
if (point->y < bottom)
270
else if (point->y > top)
276
// *y = (double)(((m_ypos + region->m_y) - (region->m_height/2.0)) + (nth + 1)*region->m_height/(no_arcs+1));
277
*y = (double)(top + (nth + 1) * region->m_height / (no_arcs + 1));
280
*y = (double)(m_ypos + region->m_y);
292
int wxDividedShape::GetNumberOfAttachments() const
294
// There are two attachments for each region (left and right),
295
// plus one on the top and one on the bottom.
296
int n = (GetRegions().GetCount() * 2) + 2;
299
wxNode *node = m_attachmentPoints.GetFirst();
302
wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
303
if (point->m_id > maxN)
305
node = node->GetNext();
310
bool wxDividedShape::AttachmentIsValid(int attachment) const
312
int totalNumberAttachments = (GetRegions().GetCount() * 2) + 2;
313
if (attachment >= totalNumberAttachments)
315
return wxShape::AttachmentIsValid(attachment);
317
else if (attachment >= 0)
323
void wxDividedShape::Copy(wxShape ©)
325
wxRectangleShape::Copy(copy);
330
void wxDividedShape::MakeControlPoints()
332
wxRectangleShape::MakeControlPoints();
334
MakeMandatoryControlPoints();
337
void wxDividedShape::MakeMandatoryControlPoints()
339
double currentY = (double)(GetY() - (m_height / 2.0));
340
double maxY = (double)(GetY() + (m_height / 2.0));
342
wxNode *node = GetRegions().GetFirst();
346
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
348
double proportion = region->m_regionProportionY;
350
double y = currentY + m_height * proportion;
351
double actualY = (double)(maxY < y ? maxY : y);
355
wxDividedShapeControlPoint *controlPoint =
356
new wxDividedShapeControlPoint(m_canvas, this, i, CONTROL_POINT_SIZE, 0.0, (double)(actualY - GetY()), 0);
357
m_canvas->AddShape(controlPoint);
358
m_controlPoints.Append(controlPoint);
362
node = node->GetNext();
366
void wxDividedShape::ResetControlPoints()
368
// May only have the region handles, (n - 1) of them.
369
if (m_controlPoints.GetCount() > (GetRegions().GetCount() - 1))
370
wxRectangleShape::ResetControlPoints();
372
ResetMandatoryControlPoints();
375
void wxDividedShape::ResetMandatoryControlPoints()
377
double currentY = (double)(GetY() - (m_height / 2.0));
378
double maxY = (double)(GetY() + (m_height / 2.0));
380
wxNode *node = m_controlPoints.GetFirst();
384
wxControlPoint *controlPoint = (wxControlPoint *)node->GetData();
385
if (controlPoint->IsKindOf(CLASSINFO(wxDividedShapeControlPoint)))
387
wxNode *node1 = GetRegions().Item(i);
388
wxShapeRegion *region = (wxShapeRegion *)node1->GetData();
390
double proportion = region->m_regionProportionY;
392
double y = currentY + m_height * proportion;
393
double actualY = (double)(maxY < y ? maxY : y);
395
controlPoint->m_xoffset = 0.0;
396
controlPoint->m_yoffset = (double)(actualY - GetY());
400
node = node->GetNext();
405
void wxDividedShape::WriteAttributes(wxExpr *clause)
407
wxRectangleShape::WriteAttributes(clause);
410
void wxDividedShape::ReadAttributes(wxExpr *clause)
412
wxRectangleShape::ReadAttributes(clause);
417
* Edit the division colour/style
421
void wxDividedShape::EditRegions()
423
wxMessageBox(wxT("EditRegions() is unimplemented."), wxT("OGL"), wxOK);
427
if (GetRegions().GetCount() < 2)
432
GraphicsForm *form = new GraphicsForm("Divided nodes");
433
// Need an array to store all the style strings,
434
// since they need to be converted to integers
435
char **styleStrings = new char *[GetRegions().GetCount()];
436
for (int j = 0; j < GetRegions().GetCount(); j++)
437
styleStrings[j] = NULL;
440
wxNode *node = GetRegions().GetFirst();
441
while (node && node->GetNext())
443
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
445
sprintf(buf, "Region %d", (i + 1));
446
form->Add(wxMakeFormMessage(buf));
447
form->Add(wxMakeFormNewLine());
449
form->Add(wxMakeFormString("Colour", ®ion->penColour, wxFORM_CHOICE,
450
new wxList(wxMakeConstraintStrings(
475
NULL), NULL, wxVERTICAL, 150));
477
char *styleString = NULL;
478
switch (region->penStyle)
481
styleString = "Short Dash";
484
styleString = "Long Dash";
490
styleString = "Dot Dash";
494
styleString = "Solid";
497
styleStrings[i] = oglCopystring(styleString);
498
form->Add(wxMakeFormString("Style", &(styleStrings[i]), wxFORM_CHOICE,
499
new wxList(wxMakeConstraintStrings(
506
NULL), NULL, wxVERTICAL, 100));
507
node = node->GetNext();
509
if (node && node->GetNext())
510
form->Add(wxMakeFormNewLine());
512
wxDialogBox *dialog = new wxDialogBox(m_canvas->GetParent(), "Divided object properties", 10, 10, 500, 500);
513
if (GraphicsLabelFont)
514
dialog->SetLabelFont(GraphicsLabelFont);
515
if (GraphicsButtonFont)
516
dialog->SetButtonFont(GraphicsButtonFont);
517
form->AssociatePanel(dialog);
518
form->dialog = dialog;
521
dialog->Centre(wxBOTH);
527
node = GetRegions().GetFirst();
531
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
535
if (strcmp(styleStrings[i], "Solid") == 0)
536
region->penStyle = wxSOLID;
537
else if (strcmp(styleStrings[i], "Dot") == 0)
538
region->penStyle = wxDOT;
539
else if (strcmp(styleStrings[i], "Short Dash") == 0)
540
region->penStyle = wxSHORT_DASH;
541
else if (strcmp(styleStrings[i], "Long Dash") == 0)
542
region->penStyle = wxLONG_DASH;
543
else if (strcmp(styleStrings[i], "Dot Dash") == 0)
544
region->penStyle = wxDOT_DASH;
545
delete[] styleStrings[i];
547
region->m_actualPenObject = NULL;
548
node = node->GetNext();
551
delete[] styleStrings;
556
void wxDividedShape::OnRightClick(double x, double y, int keys, int attachment)
564
wxRectangleShape::OnRightClick(x, y, keys, attachment);
568
wxDividedShapeControlPoint::wxDividedShapeControlPoint(wxShapeCanvas *the_canvas, wxShape *object,
569
int region, double size, double the_m_xoffset, double the_m_yoffset, int the_type):
570
wxControlPoint(the_canvas, object, size, the_m_xoffset, the_m_yoffset, the_type)
575
wxDividedShapeControlPoint::~wxDividedShapeControlPoint()
579
// Implement resizing of divided object division
580
void wxDividedShapeControlPoint::OnDragLeft(bool WXUNUSED(draw), double WXUNUSED(x), double y, int WXUNUSED(keys), int WXUNUSED(attachment))
582
wxClientDC dc(GetCanvas());
583
GetCanvas()->PrepareDC(dc);
585
dc.SetLogicalFunction(OGLRBLF);
586
wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
587
dc.SetPen(dottedPen);
588
dc.SetBrush((* wxTRANSPARENT_BRUSH));
590
wxDividedShape *dividedObject = (wxDividedShape *)m_shape;
591
double x1 = (double)(dividedObject->GetX() - (dividedObject->GetWidth() / 2.0));
593
double x2 = (double)(dividedObject->GetX() + (dividedObject->GetWidth() / 2.0));
595
dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y2));
598
void wxDividedShapeControlPoint::OnBeginDragLeft(double WXUNUSED(x), double y, int WXUNUSED(keys), int WXUNUSED(attachment))
600
wxClientDC dc(GetCanvas());
601
GetCanvas()->PrepareDC(dc);
603
wxDividedShape *dividedObject = (wxDividedShape *)m_shape;
604
dc.SetLogicalFunction(OGLRBLF);
605
wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
606
dc.SetPen(dottedPen);
607
dc.SetBrush((* wxTRANSPARENT_BRUSH));
609
double x1 = (double)(dividedObject->GetX() - (dividedObject->GetWidth() / 2.0));
611
double x2 = (double)(dividedObject->GetX() + (dividedObject->GetWidth() / 2.0));
613
dc.DrawLine(WXROUND(x1), WXROUND(y1), WXROUND(x2), WXROUND(y2));
614
m_canvas->CaptureMouse();
617
void wxDividedShapeControlPoint::OnEndDragLeft(double WXUNUSED(x), double y, int WXUNUSED(keys), int WXUNUSED(attachment))
619
wxClientDC dc(GetCanvas());
620
GetCanvas()->PrepareDC(dc);
622
wxDividedShape *dividedObject = (wxDividedShape *)m_shape;
623
wxNode *node = dividedObject->GetRegions().Item(regionId);
627
wxShapeRegion *thisRegion = (wxShapeRegion *)node->GetData();
628
wxShapeRegion *nextRegion = NULL; // Region below this one
630
dc.SetLogicalFunction(wxCOPY);
632
m_canvas->ReleaseMouse();
634
// Find the old top and bottom of this region,
635
// and calculate the new proportion for this region
638
double currentY = (double)(dividedObject->GetY() - (dividedObject->GetHeight() / 2.0));
639
double maxY = (double)(dividedObject->GetY() + (dividedObject->GetHeight() / 2.0));
642
double thisRegionTop = 0.0;
644
// this variable is not readed later
645
double thisRegionBottom = 0.0;
647
double nextRegionBottom = 0.0;
649
node = dividedObject->GetRegions().GetFirst();
652
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
654
double proportion = region->m_regionProportionY;
655
double yy = currentY + (dividedObject->GetHeight() * proportion);
656
double actualY = (double)(maxY < yy ? maxY : yy);
658
if (region == thisRegion)
660
thisRegionTop = currentY;
662
// no need for assignment if value is not used later
663
thisRegionBottom = actualY;
666
nextRegion = (wxShapeRegion *)node->GetNext()->GetData();
668
if (region == nextRegion)
670
nextRegionBottom = actualY;
674
node = node->GetNext();
679
// Check that we haven't gone above this region or below
681
if ((y <= thisRegionTop) || (y >= nextRegionBottom))
684
// dividedObject->EraseLinks(dc);
686
// Now calculate the new proportions of this region and the next region.
687
double thisProportion = (double)((y - thisRegionTop) / dividedObject->GetHeight());
688
double nextProportion = (double)((nextRegionBottom - y) / dividedObject->GetHeight());
689
thisRegion->SetProportions(0.0, thisProportion);
690
nextRegion->SetProportions(0.0, nextProportion);
691
m_yoffset = (double)(y - dividedObject->GetY());
695
node = dividedObject->GetRegions().GetFirst();
698
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
699
if (!region->GetText().IsEmpty())
701
wxChar *s = oglCopystring(region->GetText());
702
dividedObject->FormatText(dc, s, i);
705
node = node->GetNext();
708
dividedObject->SetRegionSizes();
709
dividedObject->GetEventHandler()->OnMoveLinks();
712
GetCanvas()->Refresh();