mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 14:15:49 -06:00
2498 lines
64 KiB
C++
2498 lines
64 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Portions Copyright (C) 1998 - 2011, Julian Smart
|
|
// Portions Copyright (C) 2011 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// lines.cpp - wxLineShape
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pgAdmin3.h"
|
|
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
|
|
#include "ogl/ogl.h"
|
|
|
|
|
|
// Line shape
|
|
IMPLEMENT_DYNAMIC_CLASS(wxLineShape, wxShape)
|
|
|
|
wxLineShape::wxLineShape()
|
|
{
|
|
m_sensitivity = OP_CLICK_LEFT | OP_CLICK_RIGHT;
|
|
m_draggable = FALSE;
|
|
m_attachmentTo = 0;
|
|
m_attachmentFrom = 0;
|
|
/*
|
|
m_actualTextWidth = 0.0;
|
|
m_actualTextHeight = 0.0;
|
|
*/
|
|
m_from = NULL;
|
|
m_to = NULL;
|
|
m_erasing = FALSE;
|
|
m_arrowSpacing = 5.0; // For the moment, don't bother saving this to file.
|
|
m_ignoreArrowOffsets = FALSE;
|
|
m_isSpline = FALSE;
|
|
m_maintainStraightLines = FALSE;
|
|
m_alignmentStart = 0;
|
|
m_alignmentEnd = 0;
|
|
|
|
m_lineControlPoints = NULL;
|
|
|
|
// Clear any existing regions (created in an earlier constructor)
|
|
// and make the three line regions.
|
|
ClearRegions();
|
|
wxShapeRegion *newRegion = new wxShapeRegion;
|
|
newRegion->SetName(wxT("Middle"));
|
|
newRegion->SetSize(150, 50);
|
|
m_regions.Append((wxObject *)newRegion);
|
|
|
|
newRegion = new wxShapeRegion;
|
|
newRegion->SetName(wxT("Start"));
|
|
newRegion->SetSize(150, 50);
|
|
m_regions.Append((wxObject *)newRegion);
|
|
|
|
newRegion = new wxShapeRegion;
|
|
newRegion->SetName(wxT("End"));
|
|
newRegion->SetSize(150, 50);
|
|
m_regions.Append((wxObject *)newRegion);
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
m_labelObjects[i] = NULL;
|
|
}
|
|
|
|
wxLineShape::~wxLineShape()
|
|
{
|
|
if (m_lineControlPoints)
|
|
{
|
|
ClearPointList(*m_lineControlPoints);
|
|
delete m_lineControlPoints;
|
|
}
|
|
ClearArrowsAtPosition(-1);
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (m_labelObjects[i])
|
|
{
|
|
if (m_labelObjects[i]->Selected() && m_canvas)
|
|
m_labelObjects[i]->Select(FALSE);
|
|
if (m_canvas)
|
|
m_labelObjects[i]->RemoveFromCanvas(m_canvas);
|
|
delete m_labelObjects[i];
|
|
m_labelObjects[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove any child shapes before deleting shape.
|
|
void wxLineShape::RemoveChildren()
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (m_labelObjects[i])
|
|
{
|
|
if (m_labelObjects[i]->Selected() && m_canvas)
|
|
m_labelObjects[i]->Select(FALSE);
|
|
if (m_canvas)
|
|
m_labelObjects[i]->RemoveFromCanvas(m_canvas);
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxLineShape::SetCanvas(wxShapeCanvas *the_canvas)
|
|
{
|
|
wxShape::SetCanvas(the_canvas);
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (m_labelObjects[i])
|
|
{
|
|
m_labelObjects[i]->SetCanvas(the_canvas);
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxLineShape::MakeLineControlPoints(int n)
|
|
{
|
|
if (m_lineControlPoints)
|
|
{
|
|
ClearPointList(*m_lineControlPoints);
|
|
delete m_lineControlPoints;
|
|
}
|
|
m_lineControlPoints = new wxList;
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
wxRealPoint *point = new wxRealPoint(-999, -999);
|
|
m_lineControlPoints->Append((wxObject *) point);
|
|
}
|
|
}
|
|
|
|
wxNode *wxLineShape::InsertLineControlPoint()
|
|
{
|
|
Refresh();
|
|
|
|
wxNode *last = m_lineControlPoints->GetLast();
|
|
wxNode *second_last = last->GetPrevious();
|
|
wxRealPoint *last_point = (wxRealPoint *)last->GetData();
|
|
wxRealPoint *second_last_point = (wxRealPoint *)second_last->GetData();
|
|
|
|
// Choose a point half way between the last and penultimate points
|
|
double line_x = ((last_point->x + second_last_point->x) / 2);
|
|
double line_y = ((last_point->y + second_last_point->y) / 2);
|
|
|
|
wxRealPoint *point = new wxRealPoint(line_x, line_y);
|
|
wxNode *node = m_lineControlPoints->Insert(last, (wxObject *) point);
|
|
|
|
Refresh();
|
|
|
|
return node;
|
|
}
|
|
|
|
bool wxLineShape::DeleteLineControlPoint()
|
|
{
|
|
if (m_lineControlPoints->GetCount() < 3)
|
|
return FALSE;
|
|
|
|
wxNode *last = m_lineControlPoints->GetLast();
|
|
wxNode *second_last = last->GetPrevious();
|
|
|
|
wxRealPoint *second_last_point = (wxRealPoint *)second_last->GetData();
|
|
delete second_last_point;
|
|
delete second_last;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void wxLineShape::Initialise()
|
|
{
|
|
if (m_lineControlPoints)
|
|
{
|
|
// Just move the first and last control points
|
|
wxNode *first = m_lineControlPoints->GetFirst();
|
|
wxRealPoint *first_point = (wxRealPoint *)first->GetData();
|
|
|
|
wxNode *last = m_lineControlPoints->GetLast();
|
|
wxRealPoint *last_point = (wxRealPoint *)last->GetData();
|
|
|
|
// If any of the line points are at -999, we must
|
|
// initialize them by placing them half way between the first
|
|
// and the last.
|
|
wxNode *node = first->GetNext();
|
|
while (node)
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *)node->GetData();
|
|
if (point->x == -999)
|
|
{
|
|
double x1, y1, x2, y2;
|
|
if (first_point->x < last_point->x)
|
|
{
|
|
x1 = first_point->x;
|
|
x2 = last_point->x;
|
|
}
|
|
else
|
|
{
|
|
x2 = first_point->x;
|
|
x1 = last_point->x;
|
|
}
|
|
|
|
if (first_point->y < last_point->y)
|
|
{
|
|
y1 = first_point->y;
|
|
y2 = last_point->y;
|
|
}
|
|
else
|
|
{
|
|
y2 = first_point->y;
|
|
y1 = last_point->y;
|
|
}
|
|
|
|
point->x = ((x2 - x1) / 2 + x1);
|
|
point->y = ((y2 - y1) / 2 + y1);
|
|
}
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Format a text string according to the region size, adding
|
|
// strings with positions to region text list
|
|
void wxLineShape::FormatText(wxDC &dc, const wxString &s, int i)
|
|
{
|
|
double w, h;
|
|
ClearText(i);
|
|
|
|
if (m_regions.GetCount() < 1)
|
|
return;
|
|
wxNode *node = m_regions.Item(i);
|
|
if (!node)
|
|
return;
|
|
|
|
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
|
|
region->SetText(s);
|
|
dc.SetFont(* region->GetFont());
|
|
|
|
region->GetSize(&w, &h);
|
|
// Initialize the size if zero
|
|
if (((w == 0) || (h == 0)) && (s.Length() > 0))
|
|
{
|
|
w = 100;
|
|
h = 50;
|
|
region->SetSize(w, h);
|
|
}
|
|
|
|
wxArrayString *string_list = oglFormatText(dc, s, (w - 5), (h - 5), region->GetFormatMode());
|
|
size_t j;
|
|
for (j = 0; j < string_list->GetCount(); j++)
|
|
{
|
|
const wxString &s = (*string_list)[j];
|
|
wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s);
|
|
region->GetFormattedText().Append((wxObject *)line);
|
|
}
|
|
delete string_list;
|
|
double actualW = w;
|
|
double actualH = h;
|
|
if (region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS)
|
|
{
|
|
oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH);
|
|
if ((actualW != w ) || (actualH != h))
|
|
{
|
|
double xx, yy;
|
|
GetLabelPosition(i, &xx, &yy);
|
|
if (m_labelObjects[i])
|
|
{
|
|
m_labelObjects[i]->Select(FALSE);
|
|
m_labelObjects[i]->SetSize(actualW, actualH);
|
|
}
|
|
|
|
region->SetSize(actualW, actualH);
|
|
|
|
if (m_labelObjects[i])
|
|
{
|
|
m_labelObjects[i]->Select(TRUE);
|
|
m_labelObjects[i]->Draw(dc);
|
|
}
|
|
}
|
|
}
|
|
oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode());
|
|
m_formatted = TRUE;
|
|
}
|
|
|
|
void wxLineShape::DrawRegion(wxDC &dc, wxShapeRegion *region, double x, double y)
|
|
{
|
|
if (GetDisableLabel())
|
|
return;
|
|
|
|
double w, h;
|
|
double xx, yy;
|
|
region->GetSize(&w, &h);
|
|
|
|
// Get offset from x, y
|
|
region->GetPosition(&xx, &yy);
|
|
|
|
double xp = xx + x;
|
|
double yp = yy + y;
|
|
|
|
// First, clear a rectangle for the text IF there is any
|
|
if (region->GetFormattedText().GetCount() > 0)
|
|
{
|
|
dc.SetPen(GetBackgroundPen());
|
|
dc.SetBrush(GetBackgroundBrush());
|
|
|
|
// Now draw the text
|
|
if (region->GetFont()) dc.SetFont(* region->GetFont());
|
|
|
|
dc.DrawRectangle((long)(xp - w / 2.0), (long)(yp - h / 2.0), (long)w, (long)h);
|
|
|
|
if (m_pen) dc.SetPen(* m_pen);
|
|
dc.SetTextForeground(region->GetActualColourObject());
|
|
|
|
#ifdef __WXMSW__
|
|
dc.SetTextBackground(GetBackgroundBrush().GetColour());
|
|
#endif
|
|
|
|
oglDrawFormattedText(dc, &(region->GetFormattedText()), xp, yp, w, h, region->GetFormatMode());
|
|
}
|
|
}
|
|
|
|
// Get the reference point for a label. Region x and y
|
|
// are offsets from this.
|
|
// position is 0, 1, 2
|
|
void wxLineShape::GetLabelPosition(int position, double *x, double *y)
|
|
{
|
|
switch (position)
|
|
{
|
|
case 0:
|
|
{
|
|
// Want to take the middle section for the label
|
|
int n = m_lineControlPoints->GetCount();
|
|
int half_way = (int)(n / 2);
|
|
|
|
// Find middle of this line
|
|
wxNode *node = m_lineControlPoints->Item(half_way - 1);
|
|
wxRealPoint *point = (wxRealPoint *)node->GetData();
|
|
wxNode *next_node = node->GetNext();
|
|
wxRealPoint *next_point = (wxRealPoint *)next_node->GetData();
|
|
|
|
double dx = (next_point->x - point->x);
|
|
double dy = (next_point->y - point->y);
|
|
*x = (double)(point->x + dx / 2.0);
|
|
*y = (double)(point->y + dy / 2.0);
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
wxNode *node = m_lineControlPoints->GetFirst();
|
|
*x = ((wxRealPoint *)node->GetData())->x;
|
|
*y = ((wxRealPoint *)node->GetData())->y;
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
wxNode *node = m_lineControlPoints->GetLast();
|
|
*x = ((wxRealPoint *)node->GetData())->x;
|
|
*y = ((wxRealPoint *)node->GetData())->y;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Find whether line is supposed to be vertical or horizontal and
|
|
* make it so.
|
|
*
|
|
*/
|
|
void GraphicsStraightenLine(wxRealPoint *point1, wxRealPoint *point2)
|
|
{
|
|
double dx = point2->x - point1->x;
|
|
double dy = point2->y - point1->y;
|
|
|
|
if (dx == 0.0)
|
|
return;
|
|
else if (fabs(dy / dx) > 1.0)
|
|
{
|
|
point2->x = point1->x;
|
|
}
|
|
else point2->y = point1->y;
|
|
}
|
|
|
|
void wxLineShape::Straighten()
|
|
{
|
|
if (!m_lineControlPoints || m_lineControlPoints->GetCount() < 3)
|
|
return;
|
|
|
|
Refresh();
|
|
|
|
wxNode *first_point_node = m_lineControlPoints->GetFirst();
|
|
wxNode *last_point_node = m_lineControlPoints->GetLast();
|
|
wxNode *second_last_point_node = last_point_node->GetPrevious();
|
|
|
|
wxRealPoint *last_point = (wxRealPoint *)last_point_node->GetData();
|
|
wxRealPoint *second_last_point = (wxRealPoint *)second_last_point_node->GetData();
|
|
|
|
GraphicsStraightenLine(last_point, second_last_point);
|
|
|
|
wxNode *node = first_point_node;
|
|
while (node && (node != second_last_point_node))
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *)node->GetData();
|
|
wxRealPoint *next_point = (wxRealPoint *)(node->GetNext()->GetData());
|
|
|
|
GraphicsStraightenLine(point, next_point);
|
|
node = node->GetNext();
|
|
}
|
|
|
|
Refresh();
|
|
}
|
|
|
|
|
|
void wxLineShape::Unlink()
|
|
{
|
|
if (m_to)
|
|
m_to->GetLines().DeleteObject(this);
|
|
if (m_from)
|
|
m_from->GetLines().DeleteObject(this);
|
|
m_to = NULL;
|
|
m_from = NULL;
|
|
}
|
|
|
|
void wxLineShape::SetEnds(double x1, double y1, double x2, double y2)
|
|
{
|
|
// Find centre point
|
|
wxNode *first_point_node = m_lineControlPoints->GetFirst();
|
|
wxNode *last_point_node = m_lineControlPoints->GetLast();
|
|
wxRealPoint *first_point = (wxRealPoint *)first_point_node->GetData();
|
|
wxRealPoint *last_point = (wxRealPoint *)last_point_node->GetData();
|
|
|
|
first_point->x = x1;
|
|
first_point->y = y1;
|
|
last_point->x = x2;
|
|
last_point->y = y2;
|
|
|
|
m_xpos = (double)((x1 + x2) / 2.0);
|
|
m_ypos = (double)((y1 + y2) / 2.0);
|
|
}
|
|
|
|
// Get absolute positions of ends
|
|
void wxLineShape::GetEnds(double *x1, double *y1, double *x2, double *y2)
|
|
{
|
|
wxNode *first_point_node = m_lineControlPoints->GetFirst();
|
|
wxNode *last_point_node = m_lineControlPoints->GetLast();
|
|
wxRealPoint *first_point = (wxRealPoint *)first_point_node->GetData();
|
|
wxRealPoint *last_point = (wxRealPoint *)last_point_node->GetData();
|
|
|
|
*x1 = first_point->x;
|
|
*y1 = first_point->y;
|
|
*x2 = last_point->x;
|
|
*y2 = last_point->y;
|
|
}
|
|
|
|
void wxLineShape::SetAttachments(int from_attach, int to_attach)
|
|
{
|
|
m_attachmentFrom = from_attach;
|
|
m_attachmentTo = to_attach;
|
|
}
|
|
|
|
bool wxLineShape::HitTest(double x, double y, int *attachment, double *distance)
|
|
{
|
|
if (!m_lineControlPoints)
|
|
return FALSE;
|
|
|
|
// Look at label regions in case mouse is over a label
|
|
bool inLabelRegion = FALSE;
|
|
for (int i = 0; i < 3; i ++)
|
|
{
|
|
wxNode *regionNode = m_regions.Item(i);
|
|
if (regionNode)
|
|
{
|
|
wxShapeRegion *region = (wxShapeRegion *)regionNode->GetData();
|
|
if (region->m_formattedText.GetCount() > 0)
|
|
{
|
|
double xp, yp, cx, cy, cw, ch;
|
|
GetLabelPosition(i, &xp, &yp);
|
|
// Offset region from default label position
|
|
region->GetPosition(&cx, &cy);
|
|
region->GetSize(&cw, &ch);
|
|
cx += xp;
|
|
cy += yp;
|
|
double rLeft = (double)(cx - (cw / 2.0));
|
|
double rTop = (double)(cy - (ch / 2.0));
|
|
double rRight = (double)(cx + (cw / 2.0));
|
|
double rBottom = (double)(cy + (ch / 2.0));
|
|
if (x > rLeft && x < rRight && y > rTop && y < rBottom)
|
|
{
|
|
inLabelRegion = TRUE;
|
|
i = 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wxNode *node = m_lineControlPoints->GetFirst();
|
|
|
|
while (node && node->GetNext())
|
|
{
|
|
wxRealPoint *point1 = (wxRealPoint *)node->GetData();
|
|
wxRealPoint *point2 = (wxRealPoint *)node->GetNext()->GetData();
|
|
|
|
// For inaccurate mousing allow 8 pixel corridor
|
|
int extra = 4;
|
|
|
|
double dx = point2->x - point1->x;
|
|
double dy = point2->y - point1->y;
|
|
double seg_len = sqrt(dx * dx + dy * dy);
|
|
double distance_from_seg =
|
|
seg_len * ((x - point1->x) * dy - (y - point1->y) * dx) / (dy * dy + dx * dx);
|
|
double distance_from_prev =
|
|
seg_len * ((y - point1->y) * dy + (x - point1->x) * dx) / (dy * dy + dx * dx);
|
|
|
|
if ((fabs(distance_from_seg) < extra &&
|
|
distance_from_prev >= 0 && distance_from_prev <= seg_len)
|
|
|| inLabelRegion)
|
|
{
|
|
*attachment = 0;
|
|
*distance = distance_from_seg;
|
|
return TRUE;
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void wxLineShape::DrawArrows(wxDC &dc)
|
|
{
|
|
// Distance along line of each arrow: space them out evenly.
|
|
double startArrowPos = 0.0;
|
|
double endArrowPos = 0.0;
|
|
double middleArrowPos = 0.0;
|
|
|
|
wxNode *node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrow = (wxArrowHead *)node->GetData();
|
|
switch (arrow->GetArrowEnd())
|
|
{
|
|
case ARROW_POSITION_START:
|
|
{
|
|
if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets)
|
|
// If specified, x offset is proportional to line length
|
|
DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE);
|
|
else
|
|
{
|
|
DrawArrow(dc, arrow, startArrowPos, FALSE); // Absolute distance
|
|
startArrowPos += arrow->GetSize() + arrow->GetSpacing();
|
|
}
|
|
break;
|
|
}
|
|
case ARROW_POSITION_END:
|
|
{
|
|
if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets)
|
|
DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE);
|
|
else
|
|
{
|
|
DrawArrow(dc, arrow, endArrowPos, FALSE);
|
|
endArrowPos += arrow->GetSize() + arrow->GetSpacing();
|
|
}
|
|
break;
|
|
}
|
|
case ARROW_POSITION_MIDDLE:
|
|
{
|
|
arrow->SetXOffset(middleArrowPos);
|
|
if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets)
|
|
DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE);
|
|
else
|
|
{
|
|
DrawArrow(dc, arrow, middleArrowPos, FALSE);
|
|
middleArrowPos += arrow->GetSize() + arrow->GetSpacing();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
void wxLineShape::DrawArrow(wxDC &dc, wxArrowHead *arrow, double xOffset, bool proportionalOffset)
|
|
{
|
|
wxNode *first_line_node = m_lineControlPoints->GetFirst();
|
|
wxRealPoint *first_line_point = (wxRealPoint *)first_line_node->GetData();
|
|
wxNode *second_line_node = first_line_node->GetNext();
|
|
wxRealPoint *second_line_point = (wxRealPoint *)second_line_node->GetData();
|
|
|
|
wxNode *last_line_node = m_lineControlPoints->GetLast();
|
|
wxRealPoint *last_line_point = (wxRealPoint *)last_line_node->GetData();
|
|
wxNode *second_last_line_node = last_line_node->GetPrevious();
|
|
wxRealPoint *second_last_line_point = (wxRealPoint *)second_last_line_node->GetData();
|
|
|
|
// Position where we want to start drawing
|
|
double positionOnLineX, positionOnLineY;
|
|
|
|
// Position of start point of line, at the end of which we draw the arrow.
|
|
double startPositionX = 0.0 , startPositionY = 0.0;
|
|
|
|
switch (arrow->GetPosition())
|
|
{
|
|
case ARROW_POSITION_START:
|
|
{
|
|
// If we're using a proportional offset, calculate just where this will
|
|
// be on the line.
|
|
double realOffset = xOffset;
|
|
if (proportionalOffset)
|
|
{
|
|
double totalLength =
|
|
(double)sqrt((second_line_point->x - first_line_point->x) * (second_line_point->x - first_line_point->x) +
|
|
(second_line_point->y - first_line_point->y) * (second_line_point->y - first_line_point->y));
|
|
realOffset = (double)(xOffset * totalLength);
|
|
}
|
|
GetPointOnLine(second_line_point->x, second_line_point->y,
|
|
first_line_point->x, first_line_point->y,
|
|
realOffset, &positionOnLineX, &positionOnLineY);
|
|
startPositionX = second_line_point->x;
|
|
startPositionY = second_line_point->y;
|
|
break;
|
|
}
|
|
case ARROW_POSITION_END:
|
|
{
|
|
// If we're using a proportional offset, calculate just where this will
|
|
// be on the line.
|
|
double realOffset = xOffset;
|
|
if (proportionalOffset)
|
|
{
|
|
double totalLength =
|
|
(double)sqrt((second_last_line_point->x - last_line_point->x) * (second_last_line_point->x - last_line_point->x) +
|
|
(second_last_line_point->y - last_line_point->y) * (second_last_line_point->y - last_line_point->y));
|
|
realOffset = (double)(xOffset * totalLength);
|
|
}
|
|
GetPointOnLine(second_last_line_point->x, second_last_line_point->y,
|
|
last_line_point->x, last_line_point->y,
|
|
realOffset, &positionOnLineX, &positionOnLineY);
|
|
startPositionX = second_last_line_point->x;
|
|
startPositionY = second_last_line_point->y;
|
|
break;
|
|
}
|
|
case ARROW_POSITION_MIDDLE:
|
|
{
|
|
// Choose a point half way between the last and penultimate points
|
|
double x = ((last_line_point->x + second_last_line_point->x) / 2);
|
|
double y = ((last_line_point->y + second_last_line_point->y) / 2);
|
|
|
|
// If we're using a proportional offset, calculate just where this will
|
|
// be on the line.
|
|
double realOffset = xOffset;
|
|
if (proportionalOffset)
|
|
{
|
|
double totalLength =
|
|
(double)sqrt((second_last_line_point->x - x) * (second_last_line_point->x - x) +
|
|
(second_last_line_point->y - y) * (second_last_line_point->y - y));
|
|
realOffset = (double)(xOffset * totalLength);
|
|
}
|
|
|
|
GetPointOnLine(second_last_line_point->x, second_last_line_point->y,
|
|
x, y, realOffset, &positionOnLineX, &positionOnLineY);
|
|
startPositionX = second_last_line_point->x;
|
|
startPositionY = second_last_line_point->y;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add yOffset to arrow, if any
|
|
*/
|
|
|
|
const double myPi = (double) 3.14159265;
|
|
// The translation that the y offset may give
|
|
double deltaX = 0.0;
|
|
double deltaY = 0.0;
|
|
if ((arrow->GetYOffset() != 0.0) && !m_ignoreArrowOffsets)
|
|
{
|
|
/*
|
|
|(x4, y4)
|
|
|d
|
|
|
|
|
(x1, y1)--------------(x3, y3)------------------(x2, y2)
|
|
x4 = x3 - d * sin(theta)
|
|
y4 = y3 + d * cos(theta)
|
|
|
|
Where theta = tan(-1) of (y3-y1)/(x3-x1)
|
|
*/
|
|
double x1 = startPositionX;
|
|
double y1 = startPositionY;
|
|
double x3 = positionOnLineX;
|
|
double y3 = positionOnLineY;
|
|
double d = -arrow->GetYOffset(); // Negate so +offset is above line
|
|
|
|
double theta;
|
|
if (x3 == x1)
|
|
theta = (double)(myPi / 2.0);
|
|
else
|
|
theta = (double)atan((y3 - y1) / (x3 - x1));
|
|
|
|
double x4 = (double)(x3 - (d * sin(theta)));
|
|
double y4 = (double)(y3 + (d * cos(theta)));
|
|
|
|
deltaX = x4 - positionOnLineX;
|
|
deltaY = y4 - positionOnLineY;
|
|
}
|
|
|
|
switch (arrow->_GetType())
|
|
{
|
|
case ARROW_ARROW:
|
|
{
|
|
double arrowLength = arrow->GetSize();
|
|
double arrowWidth = (double)(arrowLength / 3.0);
|
|
|
|
double tip_x, tip_y, side1_x, side1_y, side2_x, side2_y;
|
|
oglGetArrowPoints(startPositionX + deltaX, startPositionY + deltaY,
|
|
positionOnLineX + deltaX, positionOnLineY + deltaY,
|
|
arrowLength, arrowWidth, &tip_x, &tip_y,
|
|
&side1_x, &side1_y, &side2_x, &side2_y);
|
|
|
|
wxPoint points[4];
|
|
points[0].x = (int) tip_x;
|
|
points[0].y = (int) tip_y;
|
|
points[1].x = (int) side1_x;
|
|
points[1].y = (int) side1_y;
|
|
points[2].x = (int) side2_x;
|
|
points[2].y = (int) side2_y;
|
|
points[3].x = (int) tip_x;
|
|
points[3].y = (int) tip_y;
|
|
|
|
dc.SetPen(* m_pen);
|
|
dc.SetBrush(* m_brush);
|
|
dc.DrawPolygon(4, points);
|
|
break;
|
|
}
|
|
case ARROW_HOLLOW_CIRCLE:
|
|
case ARROW_FILLED_CIRCLE:
|
|
{
|
|
// Find point on line of centre of circle, which is a radius away
|
|
// from the end position
|
|
double diameter = (double)(arrow->GetSize());
|
|
double x, y;
|
|
GetPointOnLine(startPositionX + deltaX, startPositionY + deltaY,
|
|
positionOnLineX + deltaX, positionOnLineY + deltaY,
|
|
(double)(diameter / 2.0),
|
|
&x, &y);
|
|
|
|
// Convert ellipse centre to top-left coordinates
|
|
double x1 = (double)(x - (diameter / 2.0));
|
|
double y1 = (double)(y - (diameter / 2.0));
|
|
|
|
dc.SetPen(* m_pen);
|
|
if (arrow->_GetType() == ARROW_HOLLOW_CIRCLE)
|
|
dc.SetBrush(GetBackgroundBrush());
|
|
else
|
|
dc.SetBrush(* m_brush);
|
|
|
|
dc.DrawEllipse((long) x1, (long) y1, (long) diameter, (long) diameter);
|
|
break;
|
|
}
|
|
case ARROW_SINGLE_OBLIQUE:
|
|
{
|
|
break;
|
|
}
|
|
case ARROW_METAFILE:
|
|
{
|
|
if (arrow->GetMetaFile())
|
|
{
|
|
// Find point on line of centre of object, which is a half-width away
|
|
// from the end position
|
|
/*
|
|
* width
|
|
* <-- start pos <-----><-- positionOnLineX
|
|
* _____
|
|
* --------------| x | <-- e.g. rectangular arrowhead
|
|
* -----
|
|
*/
|
|
double x, y;
|
|
GetPointOnLine(startPositionX, startPositionY,
|
|
positionOnLineX, positionOnLineY,
|
|
(double)(arrow->GetMetaFile()->m_width / 2.0),
|
|
&x, &y);
|
|
|
|
// Calculate theta for rotating the metafile.
|
|
/*
|
|
|
|
|
| o(x2, y2) 'o' represents the arrowhead.
|
|
| /
|
|
| /
|
|
| /theta
|
|
| /(x1, y1)
|
|
|______________________
|
|
*/
|
|
double theta = 0.0;
|
|
double x1 = startPositionX;
|
|
double y1 = startPositionY;
|
|
double x2 = positionOnLineX;
|
|
double y2 = positionOnLineY;
|
|
|
|
if ((x1 == x2) && (y1 == y2))
|
|
theta = 0.0;
|
|
|
|
else if ((x1 == x2) && (y1 > y2))
|
|
theta = (double)(3.0 * myPi / 2.0);
|
|
|
|
else if ((x1 == x2) && (y2 > y1))
|
|
theta = (double)(myPi / 2.0);
|
|
|
|
else if ((x2 > x1) && (y2 >= y1))
|
|
theta = (double)atan((y2 - y1) / (x2 - x1));
|
|
|
|
else if (x2 < x1)
|
|
theta = (double)(myPi + atan((y2 - y1) / (x2 - x1)));
|
|
|
|
else if ((x2 > x1) && (y2 < y1))
|
|
theta = (double)(2 * myPi + atan((y2 - y1) / (x2 - x1)));
|
|
|
|
else
|
|
{
|
|
wxLogFatalError(wxT("Unknown arrowhead rotation case in lines.cc"));
|
|
}
|
|
|
|
// Rotate about the centre of the object, then place
|
|
// the object on the line.
|
|
if (arrow->GetMetaFile()->GetRotateable())
|
|
arrow->GetMetaFile()->Rotate(0.0, 0.0, theta);
|
|
|
|
if (m_erasing)
|
|
{
|
|
// If erasing, just draw a rectangle.
|
|
double minX, minY, maxX, maxY;
|
|
arrow->GetMetaFile()->GetBounds(&minX, &minY, &maxX, &maxY);
|
|
// Make erasing rectangle slightly bigger or you get droppings.
|
|
int extraPixels = 4;
|
|
dc.DrawRectangle((long)(deltaX + x + minX - (extraPixels / 2.0)), (long)(deltaY + y + minY - (extraPixels / 2.0)),
|
|
(long)(maxX - minX + extraPixels), (long)(maxY - minY + extraPixels));
|
|
}
|
|
else
|
|
arrow->GetMetaFile()->Draw(dc, x + deltaX, y + deltaY);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxLineShape::GetBoundingBoxMin(double *w, double *h)
|
|
{
|
|
double x1 = 10000;
|
|
double y1 = 10000;
|
|
double x2 = -10000;
|
|
double y2 = -10000;
|
|
|
|
wxNode *node = m_lineControlPoints->GetFirst();
|
|
while (node)
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *)node->GetData();
|
|
|
|
if (point->x < x1) x1 = point->x;
|
|
if (point->y < y1) y1 = point->y;
|
|
if (point->x > x2) x2 = point->x;
|
|
if (point->y > y2) y2 = point->y;
|
|
|
|
node = node->GetNext();
|
|
}
|
|
*w = (double)(x2 - x1);
|
|
*h = (double)(y2 - y1);
|
|
}
|
|
|
|
/*
|
|
* For a node image of interest, finds the position of this arc
|
|
* amongst all the arcs which are attached to THIS SIDE of the node image,
|
|
* and the number of same.
|
|
*/
|
|
void wxLineShape::FindNth(wxShape *image, int *nth, int *no_arcs, bool incoming)
|
|
{
|
|
int n = -1;
|
|
int num = 0;
|
|
wxNode *node = image->GetLines().GetFirst();
|
|
int this_attachment;
|
|
if (image == m_to)
|
|
this_attachment = m_attachmentTo;
|
|
else
|
|
this_attachment = m_attachmentFrom;
|
|
|
|
// Find number of lines going into/out of this particular attachment point
|
|
while (node)
|
|
{
|
|
wxLineShape *line = (wxLineShape *)node->GetData();
|
|
|
|
if (line->m_from == image)
|
|
{
|
|
// This is the nth line attached to 'image'
|
|
if ((line == this) && !incoming)
|
|
n = num;
|
|
|
|
// Increment num count if this is the same side (attachment number)
|
|
if (line->m_attachmentFrom == this_attachment)
|
|
num ++;
|
|
}
|
|
|
|
if (line->m_to == image)
|
|
{
|
|
// This is the nth line attached to 'image'
|
|
if ((line == this) && incoming)
|
|
n = num;
|
|
|
|
// Increment num count if this is the same side (attachment number)
|
|
if (line->m_attachmentTo == this_attachment)
|
|
num ++;
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
*nth = n;
|
|
*no_arcs = num;
|
|
}
|
|
|
|
void wxLineShape::OnDrawOutline(wxDC &dc, double WXUNUSED(x), double WXUNUSED(y), double WXUNUSED(w), double WXUNUSED(h))
|
|
{
|
|
wxPen *old_pen = m_pen;
|
|
wxBrush *old_brush = m_brush;
|
|
|
|
wxPen dottedPen(wxColour(0, 0, 0), 1, wxPENSTYLE_DOT);
|
|
SetPen(& dottedPen);
|
|
SetBrush( (wxBrush *) wxTRANSPARENT_BRUSH );
|
|
|
|
GetEventHandler()->OnDraw(dc);
|
|
|
|
if (old_pen) SetPen(old_pen);
|
|
else SetPen(NULL);
|
|
if (old_brush) SetBrush(old_brush);
|
|
else SetBrush(NULL);
|
|
}
|
|
|
|
bool wxLineShape::OnMovePre(double x, double y, double old_x, double old_y, bool WXUNUSED(display))
|
|
{
|
|
double x_offset = x - old_x;
|
|
double y_offset = y - old_y;
|
|
|
|
if (m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
|
|
{
|
|
wxNode *node = m_lineControlPoints->GetFirst();
|
|
while (node)
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *)node->GetData();
|
|
point->x += x_offset;
|
|
point->y += y_offset;
|
|
node = node->GetNext();
|
|
}
|
|
|
|
}
|
|
|
|
// Move temporary label rectangles if necessary
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (m_labelObjects[i] && m_labelObjects[i]->Selected())
|
|
{
|
|
double xp, yp, xr, yr;
|
|
GetLabelPosition(i, &xp, &yp);
|
|
wxNode *node = m_regions.Item(i);
|
|
if (node)
|
|
{
|
|
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
|
|
region->GetPosition(&xr, &yr);
|
|
}
|
|
else
|
|
{
|
|
xr = 0.0;
|
|
yr = 0.0;
|
|
}
|
|
|
|
m_labelObjects[i]->Move(xp + xr, yp + yr);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void wxLineShape::OnMoveLink(bool moveControlPoints)
|
|
{
|
|
if (!m_from || !m_to)
|
|
return;
|
|
|
|
if (m_lineControlPoints->GetCount() > 2)
|
|
Initialise();
|
|
|
|
// Do each end - nothing in the middle. User has to move other points
|
|
// manually if necessary.
|
|
double end_x, end_y;
|
|
double other_end_x, other_end_y;
|
|
|
|
FindLineEndPoints(&end_x, &end_y, &other_end_x, &other_end_y);
|
|
|
|
wxNode *first = m_lineControlPoints->GetFirst();
|
|
wxNode *last = m_lineControlPoints->GetLast();
|
|
|
|
/* This is redundant, surely? Done by SetEnds.
|
|
first_point->x = end_x; first_point->y = end_y;
|
|
last_point->x = other_end_x; last_point->y = other_end_y;
|
|
*/
|
|
|
|
double oldX = m_xpos;
|
|
double oldY = m_ypos;
|
|
|
|
SetEnds(end_x, end_y, other_end_x, other_end_y);
|
|
|
|
// Do a second time, because one may depend on the other.
|
|
FindLineEndPoints(&end_x, &end_y, &other_end_x, &other_end_y);
|
|
SetEnds(end_x, end_y, other_end_x, other_end_y);
|
|
|
|
// Try to move control points with the arc
|
|
double x_offset = m_xpos - oldX;
|
|
double y_offset = m_ypos - oldY;
|
|
|
|
// if (moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
|
|
// Only move control points if it's a self link. And only works if attachment mode is ON.
|
|
if ((m_from == m_to) && (m_from->GetAttachmentMode() != ATTACHMENT_MODE_NONE) && moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
|
|
{
|
|
wxNode *node = m_lineControlPoints->GetFirst();
|
|
while (node)
|
|
{
|
|
if ((node != m_lineControlPoints->GetFirst()) && (node != m_lineControlPoints->GetLast()))
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *)node->GetData();
|
|
point->x += x_offset;
|
|
point->y += y_offset;
|
|
}
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
Move(m_xpos, m_ypos);
|
|
}
|
|
|
|
// Finds the x, y points at the two ends of the line.
|
|
// This function can be used by e.g. line-routing routines to
|
|
// get the actual points on the two node images where the lines will be drawn
|
|
// to/from.
|
|
void wxLineShape::FindLineEndPoints(double *fromX, double *fromY, double *toX, double *toY)
|
|
{
|
|
if (!m_from || !m_to)
|
|
return;
|
|
|
|
// Do each end - nothing in the middle. User has to move other points
|
|
// manually if necessary.
|
|
double end_x, end_y;
|
|
double other_end_x, other_end_y;
|
|
|
|
wxNode *first = m_lineControlPoints->GetFirst();
|
|
wxNode *last = m_lineControlPoints->GetLast();
|
|
|
|
wxNode *second = first->GetNext();
|
|
wxRealPoint *second_point = (wxRealPoint *)second->GetData();
|
|
|
|
wxNode *second_last = last->GetPrevious();
|
|
wxRealPoint *second_last_point = (wxRealPoint *)second_last->GetData();
|
|
|
|
if (m_lineControlPoints->GetCount() > 2)
|
|
{
|
|
if (m_from->GetAttachmentMode() != ATTACHMENT_MODE_NONE)
|
|
{
|
|
int nth, no_arcs;
|
|
FindNth(m_from, &nth, &no_arcs, FALSE); // Not incoming
|
|
m_from->GetAttachmentPosition(m_attachmentFrom, &end_x, &end_y, nth, no_arcs, this);
|
|
}
|
|
else
|
|
(void) m_from->GetPerimeterPoint(m_from->GetX(), m_from->GetY(),
|
|
(double)second_point->x, (double)second_point->y,
|
|
&end_x, &end_y);
|
|
|
|
if (m_to->GetAttachmentMode() != ATTACHMENT_MODE_NONE)
|
|
{
|
|
int nth, no_arcs;
|
|
FindNth(m_to, &nth, &no_arcs, TRUE); // Incoming
|
|
m_to->GetAttachmentPosition(m_attachmentTo, &other_end_x, &other_end_y, nth, no_arcs, this);
|
|
}
|
|
else
|
|
(void) m_to->GetPerimeterPoint(m_to->GetX(), m_to->GetY(),
|
|
(double)second_last_point->x, (double)second_last_point->y,
|
|
&other_end_x, &other_end_y);
|
|
}
|
|
else
|
|
{
|
|
double fromX = m_from->GetX();
|
|
double fromY = m_from->GetY();
|
|
double toX = m_to->GetX();
|
|
double toY = m_to->GetY();
|
|
|
|
if (m_from->GetAttachmentMode() != ATTACHMENT_MODE_NONE)
|
|
{
|
|
int nth, no_arcs;
|
|
FindNth(m_from, &nth, &no_arcs, FALSE);
|
|
m_from->GetAttachmentPosition(m_attachmentFrom, &end_x, &end_y, nth, no_arcs, this);
|
|
fromX = end_x;
|
|
fromY = end_y;
|
|
}
|
|
|
|
if (m_to->GetAttachmentMode() != ATTACHMENT_MODE_NONE)
|
|
{
|
|
int nth, no_arcs;
|
|
FindNth(m_to, &nth, &no_arcs, TRUE);
|
|
m_to->GetAttachmentPosition(m_attachmentTo, &other_end_x, &other_end_y, nth, no_arcs, this);
|
|
toX = other_end_x;
|
|
toY = other_end_y;
|
|
}
|
|
|
|
if (m_from->GetAttachmentMode() == ATTACHMENT_MODE_NONE)
|
|
(void) m_from->GetPerimeterPoint(m_from->GetX(), m_from->GetY(),
|
|
toX, toY,
|
|
&end_x, &end_y);
|
|
|
|
if (m_to->GetAttachmentMode() == ATTACHMENT_MODE_NONE)
|
|
(void) m_to->GetPerimeterPoint(m_to->GetX(), m_to->GetY(),
|
|
fromX, fromY,
|
|
&other_end_x, &other_end_y);
|
|
}
|
|
*fromX = end_x;
|
|
*fromY = end_y;
|
|
*toX = other_end_x;
|
|
*toY = other_end_y;
|
|
}
|
|
|
|
void wxLineShape::OnDraw(wxDC &dc)
|
|
{
|
|
if (m_lineControlPoints)
|
|
{
|
|
if (m_pen)
|
|
dc.SetPen(* m_pen);
|
|
if (m_brush)
|
|
dc.SetBrush(* m_brush);
|
|
|
|
int n = m_lineControlPoints->GetCount();
|
|
wxPoint *points = new wxPoint[n];
|
|
int i;
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *) m_lineControlPoints->Item(i)->GetData();
|
|
points[i].x = WXROUND(point->x);
|
|
points[i].y = WXROUND(point->y);
|
|
}
|
|
|
|
if (m_isSpline)
|
|
dc.DrawSpline(n, points);
|
|
else
|
|
dc.DrawLines(n, points);
|
|
|
|
#ifdef __WXMSW__
|
|
// For some reason, last point isn't drawn under Windows.
|
|
dc.DrawPoint(points[n - 1]);
|
|
#endif
|
|
|
|
delete[] points;
|
|
|
|
|
|
// Problem with pen - if not a solid pen, does strange things
|
|
// to the arrowhead. So make (get) a new pen that's solid.
|
|
if (m_pen && (m_pen->GetStyle() != wxPENSTYLE_DOT))
|
|
{
|
|
wxPen *solid_pen =
|
|
wxThePenList->FindOrCreatePen(m_pen->GetColour(), 1, wxPENSTYLE_DOT);
|
|
if (solid_pen)
|
|
dc.SetPen(* solid_pen);
|
|
}
|
|
DrawArrows(dc);
|
|
}
|
|
}
|
|
|
|
void wxLineShape::OnDrawControlPoints(wxDC &dc)
|
|
{
|
|
if (!m_drawHandles)
|
|
return;
|
|
|
|
// Draw temporary label rectangles if necessary
|
|
if (Selected())
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (m_labelObjects[i] && m_labelObjects[i]->IsShown())
|
|
m_labelObjects[i]->Draw(dc);
|
|
}
|
|
}
|
|
wxShape::OnDrawControlPoints(dc);
|
|
}
|
|
|
|
void wxLineShape::OnDragLeft(bool WXUNUSED(draw), double WXUNUSED(x), double WXUNUSED(y), int WXUNUSED(keys), int WXUNUSED(attachment))
|
|
{
|
|
}
|
|
|
|
void wxLineShape::OnBeginDragLeft(double WXUNUSED(x), double WXUNUSED(y), int WXUNUSED(keys), int WXUNUSED(attachment))
|
|
{
|
|
}
|
|
|
|
void wxLineShape::OnEndDragLeft(double WXUNUSED(x), double WXUNUSED(y), int WXUNUSED(keys), int WXUNUSED(attachment))
|
|
{
|
|
}
|
|
|
|
/*
|
|
void wxLineShape::SetArrowSize(double length, double width)
|
|
{
|
|
arrow_length = length;
|
|
arrow_width = width;
|
|
}
|
|
|
|
void wxLineShape::SetStartArrow(int style)
|
|
{
|
|
start_style = style;
|
|
}
|
|
|
|
void wxLineShape::SetMiddleArrow(int style)
|
|
{
|
|
middle_style = style;
|
|
}
|
|
|
|
void wxLineShape::SetEndArrow(int style)
|
|
{
|
|
end_style = style;
|
|
}
|
|
*/
|
|
|
|
void wxLineShape::OnDrawContents(wxDC &dc)
|
|
{
|
|
if (GetDisableLabel())
|
|
return;
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
wxNode *node = m_regions.Item(i);
|
|
if (node)
|
|
{
|
|
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
|
|
double x, y;
|
|
GetLabelPosition(i, &x, &y);
|
|
DrawRegion(dc, region, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxLineShape::SetTo(wxShape *object)
|
|
{
|
|
m_to = object;
|
|
}
|
|
|
|
void wxLineShape::SetFrom(wxShape *object)
|
|
{
|
|
m_from = object;
|
|
}
|
|
|
|
void wxLineShape::MakeControlPoints()
|
|
{
|
|
if (m_canvas && m_lineControlPoints)
|
|
{
|
|
wxNode *first = m_lineControlPoints->GetFirst();
|
|
wxNode *last = m_lineControlPoints->GetLast();
|
|
wxRealPoint *first_point = (wxRealPoint *)first->GetData();
|
|
wxRealPoint *last_point = (wxRealPoint *)last->GetData();
|
|
|
|
wxLineControlPoint *control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
|
|
first_point->x, first_point->y,
|
|
CONTROL_POINT_ENDPOINT_FROM);
|
|
control->m_point = first_point;
|
|
m_canvas->AddShape(control);
|
|
m_controlPoints.Append(control);
|
|
|
|
|
|
wxNode *node = first->GetNext();
|
|
while (node != last)
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *)node->GetData();
|
|
|
|
control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
|
|
point->x, point->y,
|
|
CONTROL_POINT_LINE);
|
|
control->m_point = point;
|
|
|
|
m_canvas->AddShape(control);
|
|
m_controlPoints.Append(control);
|
|
|
|
node = node->GetNext();
|
|
}
|
|
control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
|
|
last_point->x, last_point->y,
|
|
CONTROL_POINT_ENDPOINT_TO);
|
|
control->m_point = last_point;
|
|
m_canvas->AddShape(control);
|
|
m_controlPoints.Append(control);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void wxLineShape::ResetControlPoints()
|
|
{
|
|
if (m_canvas && m_lineControlPoints && m_controlPoints.GetCount() > 0)
|
|
{
|
|
wxNode *node = m_controlPoints.GetFirst();
|
|
wxNode *control_node = m_lineControlPoints->GetFirst();
|
|
while (node && control_node)
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *)control_node->GetData();
|
|
wxLineControlPoint *control = (wxLineControlPoint *)node->GetData();
|
|
control->SetX(point->x);
|
|
control->SetY(point->y);
|
|
|
|
node = node->GetNext();
|
|
control_node = control_node->GetNext();
|
|
}
|
|
}
|
|
}
|
|
|
|
#if wxUSE_PROLOGIO
|
|
void wxLineShape::WriteAttributes(wxExpr *clause)
|
|
{
|
|
wxShape::WriteAttributes(clause);
|
|
|
|
if (m_from)
|
|
clause->AddAttributeValue(wxT("from"), m_from->GetId());
|
|
if (m_to)
|
|
clause->AddAttributeValue(wxT("to"), m_to->GetId());
|
|
|
|
if (m_attachmentTo != 0)
|
|
clause->AddAttributeValue(wxT("attachment_to"), (long)m_attachmentTo);
|
|
if (m_attachmentFrom != 0)
|
|
clause->AddAttributeValue(wxT("attachment_from"), (long)m_attachmentFrom);
|
|
|
|
if (m_alignmentStart != 0)
|
|
clause->AddAttributeValue(wxT("align_start"), (long)m_alignmentStart);
|
|
if (m_alignmentEnd != 0)
|
|
clause->AddAttributeValue(wxT("align_end"), (long)m_alignmentEnd);
|
|
|
|
clause->AddAttributeValue(wxT("is_spline"), (long)m_isSpline);
|
|
if (m_maintainStraightLines)
|
|
clause->AddAttributeValue(wxT("keep_lines_straight"), (long)m_maintainStraightLines);
|
|
|
|
// Make a list of lists for the (sp)line controls
|
|
wxExpr *list = new wxExpr(wxExprList);
|
|
wxNode *node = m_lineControlPoints->GetFirst();
|
|
while (node)
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *)node->GetData();
|
|
wxExpr *point_list = new wxExpr(wxExprList);
|
|
wxExpr *x_expr = new wxExpr((double) point->x);
|
|
wxExpr *y_expr = new wxExpr((double) point->y);
|
|
point_list->Append(x_expr);
|
|
point_list->Append(y_expr);
|
|
list->Append(point_list);
|
|
|
|
node = node->GetNext();
|
|
}
|
|
clause->AddAttributeValue(wxT("controls"), list);
|
|
|
|
// Write arc arrows in new OGL format, if there are any.
|
|
// This is a list of lists. Each sublist comprises:
|
|
// (arrowType arrowEnd xOffset arrowSize)
|
|
if (m_arcArrows.GetCount() > 0)
|
|
{
|
|
wxExpr *arrow_list = new wxExpr(wxExprList);
|
|
node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *head = (wxArrowHead *)node->GetData();
|
|
wxExpr *head_list = new wxExpr(wxExprList);
|
|
head_list->Append(new wxExpr((long)head->_GetType()));
|
|
head_list->Append(new wxExpr((long)head->GetArrowEnd()));
|
|
head_list->Append(new wxExpr(head->GetXOffset()));
|
|
head_list->Append(new wxExpr(head->GetArrowSize()));
|
|
head_list->Append(new wxExpr(wxExprString, head->GetName()));
|
|
head_list->Append(new wxExpr(head->GetId()));
|
|
|
|
// New members of wxArrowHead
|
|
head_list->Append(new wxExpr(head->GetYOffset()));
|
|
head_list->Append(new wxExpr(head->GetSpacing()));
|
|
|
|
arrow_list->Append(head_list);
|
|
|
|
node = node->GetNext();
|
|
}
|
|
clause->AddAttributeValue(wxT("arrows"), arrow_list);
|
|
}
|
|
}
|
|
|
|
void wxLineShape::ReadAttributes(wxExpr *clause)
|
|
{
|
|
wxShape::ReadAttributes(clause);
|
|
|
|
int iVal = (int) m_isSpline;
|
|
clause->AssignAttributeValue(wxT("is_spline"), &iVal);
|
|
m_isSpline = (iVal != 0);
|
|
|
|
iVal = (int) m_maintainStraightLines;
|
|
clause->AssignAttributeValue(wxT("keep_lines_straight"), &iVal);
|
|
m_maintainStraightLines = (iVal != 0);
|
|
|
|
clause->AssignAttributeValue(wxT("align_start"), &m_alignmentStart);
|
|
clause->AssignAttributeValue(wxT("align_end"), &m_alignmentEnd);
|
|
|
|
// Compatibility: check for no regions.
|
|
if (m_regions.GetCount() == 0)
|
|
{
|
|
wxShapeRegion *newRegion = new wxShapeRegion;
|
|
newRegion->SetName(wxT("Middle"));
|
|
newRegion->SetSize(150, 50);
|
|
m_regions.Append((wxObject *)newRegion);
|
|
if (m_text.GetCount() > 0)
|
|
{
|
|
newRegion->ClearText();
|
|
wxNode *node = m_text.GetFirst();
|
|
while (node)
|
|
{
|
|
wxShapeTextLine *textLine = (wxShapeTextLine *)node->GetData();
|
|
wxNode *next = node->GetNext();
|
|
newRegion->GetFormattedText().Append((wxObject *)textLine);
|
|
delete node;
|
|
node = next;
|
|
}
|
|
}
|
|
|
|
newRegion = new wxShapeRegion;
|
|
newRegion->SetName(wxT("Start"));
|
|
newRegion->SetSize(150, 50);
|
|
m_regions.Append((wxObject *)newRegion);
|
|
|
|
newRegion = new wxShapeRegion;
|
|
newRegion->SetName(wxT("End"));
|
|
newRegion->SetSize(150, 50);
|
|
m_regions.Append((wxObject *)newRegion);
|
|
}
|
|
|
|
m_attachmentTo = 0;
|
|
m_attachmentFrom = 0;
|
|
|
|
clause->AssignAttributeValue(wxT("attachment_to"), &m_attachmentTo);
|
|
clause->AssignAttributeValue(wxT("attachment_from"), &m_attachmentFrom);
|
|
|
|
wxExpr *line_list = NULL;
|
|
|
|
// When image is created, there are default control points. Override
|
|
// them if there are some in the file.
|
|
clause->AssignAttributeValue(wxT("controls"), &line_list);
|
|
|
|
if (line_list)
|
|
{
|
|
// Read a list of lists for the spline controls
|
|
if (m_lineControlPoints)
|
|
{
|
|
ClearPointList(*m_lineControlPoints);
|
|
}
|
|
else
|
|
m_lineControlPoints = new wxList;
|
|
|
|
wxExpr *node = line_list->value.first;
|
|
|
|
while (node)
|
|
{
|
|
wxExpr *xexpr = node->value.first;
|
|
double x = xexpr->RealValue();
|
|
|
|
wxExpr *yexpr = xexpr->next;
|
|
double y = yexpr->RealValue();
|
|
|
|
wxRealPoint *point = new wxRealPoint(x, y);
|
|
m_lineControlPoints->Append((wxObject *) point);
|
|
|
|
node = node->next;
|
|
}
|
|
}
|
|
|
|
// Read arrow list, for new OGL code
|
|
wxExpr *arrow_list = NULL;
|
|
|
|
clause->AssignAttributeValue(wxT("arrows"), &arrow_list);
|
|
if (arrow_list)
|
|
{
|
|
wxExpr *node = arrow_list->value.first;
|
|
|
|
while (node)
|
|
{
|
|
WXTYPE arrowType = ARROW_ARROW;
|
|
int arrowEnd = 0;
|
|
double xOffset = 0.0;
|
|
double arrowSize = 0.0;
|
|
wxString arrowName;
|
|
long arrowId = -1;
|
|
|
|
wxExpr *type_expr = node->Nth(0);
|
|
wxExpr *end_expr = node->Nth(1);
|
|
wxExpr *dist_expr = node->Nth(2);
|
|
wxExpr *size_expr = node->Nth(3);
|
|
wxExpr *name_expr = node->Nth(4);
|
|
wxExpr *id_expr = node->Nth(5);
|
|
|
|
// New members of wxArrowHead
|
|
wxExpr *yOffsetExpr = node->Nth(6);
|
|
wxExpr *spacingExpr = node->Nth(7);
|
|
|
|
if (type_expr)
|
|
arrowType = (int)type_expr->IntegerValue();
|
|
if (end_expr)
|
|
arrowEnd = (int)end_expr->IntegerValue();
|
|
if (dist_expr)
|
|
xOffset = dist_expr->RealValue();
|
|
if (size_expr)
|
|
arrowSize = size_expr->RealValue();
|
|
if (name_expr)
|
|
arrowName = name_expr->StringValue();
|
|
if (id_expr)
|
|
arrowId = id_expr->IntegerValue();
|
|
|
|
if (arrowId == -1)
|
|
arrowId = wxNewId();
|
|
else
|
|
wxRegisterId(arrowId);
|
|
|
|
wxArrowHead *arrowHead = AddArrow(arrowType, arrowEnd, arrowSize, xOffset, arrowName, NULL, arrowId);
|
|
if (yOffsetExpr)
|
|
arrowHead->SetYOffset(yOffsetExpr->RealValue());
|
|
if (spacingExpr)
|
|
arrowHead->SetSpacing(spacingExpr->RealValue());
|
|
|
|
node = node->next;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void wxLineShape::Copy(wxShape ©)
|
|
{
|
|
wxShape::Copy(copy);
|
|
|
|
wxASSERT( copy.IsKindOf(CLASSINFO(wxLineShape)) );
|
|
|
|
wxLineShape &lineCopy = (wxLineShape &) copy;
|
|
|
|
lineCopy.m_to = m_to;
|
|
lineCopy.m_from = m_from;
|
|
lineCopy.m_attachmentTo = m_attachmentTo;
|
|
lineCopy.m_attachmentFrom = m_attachmentFrom;
|
|
lineCopy.m_isSpline = m_isSpline;
|
|
lineCopy.m_alignmentStart = m_alignmentStart;
|
|
lineCopy.m_alignmentEnd = m_alignmentEnd;
|
|
lineCopy.m_maintainStraightLines = m_maintainStraightLines;
|
|
lineCopy.m_lineOrientations.Clear();
|
|
|
|
wxNode *node = m_lineOrientations.GetFirst();
|
|
while (node)
|
|
{
|
|
lineCopy.m_lineOrientations.Append(node->GetData());
|
|
node = node->GetNext();
|
|
}
|
|
|
|
if (lineCopy.m_lineControlPoints)
|
|
{
|
|
ClearPointList(*lineCopy.m_lineControlPoints);
|
|
delete lineCopy.m_lineControlPoints;
|
|
}
|
|
|
|
lineCopy.m_lineControlPoints = new wxList;
|
|
|
|
node = m_lineControlPoints->GetFirst();
|
|
while (node)
|
|
{
|
|
wxRealPoint *point = (wxRealPoint *)node->GetData();
|
|
wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
|
|
lineCopy.m_lineControlPoints->Append((wxObject *) new_point);
|
|
node = node->GetNext();
|
|
}
|
|
|
|
// Copy arrows
|
|
lineCopy.ClearArrowsAtPosition(-1);
|
|
node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrow = (wxArrowHead *)node->GetData();
|
|
lineCopy.m_arcArrows.Append(new wxArrowHead(*arrow));
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
// Override select, to create/delete temporary label-moving objects
|
|
void wxLineShape::Select(bool select)
|
|
{
|
|
wxShape::Select(select);
|
|
if (select)
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
wxNode *node = m_regions.Item(i);
|
|
if (node)
|
|
{
|
|
wxShapeRegion *region = (wxShapeRegion *)node->GetData();
|
|
if (region->m_formattedText.GetCount() > 0)
|
|
{
|
|
double w, h, x, y, xx, yy;
|
|
region->GetSize(&w, &h);
|
|
region->GetPosition(&x, &y);
|
|
GetLabelPosition(i, &xx, &yy);
|
|
#if 0
|
|
if (m_labelObjects[i])
|
|
{
|
|
m_labelObjects[i]->Select(FALSE);
|
|
m_labelObjects[i]->RemoveFromCanvas(m_canvas);
|
|
delete m_labelObjects[i];
|
|
}
|
|
#endif
|
|
if (!m_labelObjects[i])
|
|
{
|
|
m_labelObjects[i] = OnCreateLabelShape(this, region, w, h);
|
|
}
|
|
m_labelObjects[i]->AddToCanvas(m_canvas);
|
|
m_labelObjects[i]->Show(TRUE);
|
|
m_labelObjects[i]->Move((double)(x + xx), (double)(y + yy));
|
|
m_labelObjects[i]->Select(TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (m_labelObjects[i])
|
|
{
|
|
// Don't delete the shape, it might be mentioned in a command
|
|
m_labelObjects[i]->Select(FALSE);
|
|
m_labelObjects[i]->Show(false);
|
|
m_labelObjects[i]->RemoveFromCanvas(m_canvas);
|
|
#if 0
|
|
m_labelObjects[i]->Select(FALSE);
|
|
m_labelObjects[i]->RemoveFromCanvas(m_canvas);
|
|
delete m_labelObjects[i];
|
|
m_labelObjects[i] = NULL;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
Refresh();
|
|
}
|
|
|
|
/*
|
|
* Line control point
|
|
*
|
|
*/
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxLineControlPoint, wxControlPoint)
|
|
|
|
wxLineControlPoint::wxLineControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size, double x, double y, int the_type):
|
|
wxControlPoint(theCanvas, object, size, x, y, the_type)
|
|
{
|
|
m_xpos = x;
|
|
m_ypos = y;
|
|
m_type = the_type;
|
|
m_point = NULL;
|
|
}
|
|
|
|
wxLineControlPoint::~wxLineControlPoint()
|
|
{
|
|
}
|
|
|
|
void wxLineControlPoint::OnDraw(wxDC &dc)
|
|
{
|
|
wxRectangleShape::OnDraw(dc);
|
|
}
|
|
|
|
// Implement movement of Line point
|
|
void wxLineControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
|
|
{
|
|
m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment);
|
|
}
|
|
|
|
void wxLineControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
|
|
{
|
|
m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment);
|
|
}
|
|
|
|
void wxLineControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
|
|
{
|
|
m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment);
|
|
}
|
|
|
|
// Control points ('handles') redirect control to the actual shape, to make it easier
|
|
// to override sizing behaviour.
|
|
void wxLineShape::OnSizingDragLeft(wxControlPoint *pt, bool WXUNUSED(draw), double x, double y, int WXUNUSED(keys), int WXUNUSED(attachment))
|
|
{
|
|
wxLineControlPoint *lpt = (wxLineControlPoint *) pt;
|
|
|
|
#if 0
|
|
wxClientDC dc(GetCanvas());
|
|
GetCanvas()->PrepareDC(dc);
|
|
|
|
dc.SetLogicalFunction(OGLRBLF);
|
|
|
|
wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
|
|
dc.SetPen(dottedPen);
|
|
dc.SetBrush((* wxTRANSPARENT_BRUSH));
|
|
#endif
|
|
|
|
if (lpt->m_type == CONTROL_POINT_LINE)
|
|
{
|
|
m_canvas->Snap(&x, &y);
|
|
|
|
lpt->SetX(x);
|
|
lpt->SetY(y);
|
|
lpt->m_point->x = x;
|
|
lpt->m_point->y = y;
|
|
|
|
#if 0
|
|
wxLineShape *lineShape = (wxLineShape *)this;
|
|
|
|
wxPen *old_pen = lineShape->GetPen();
|
|
wxBrush *old_brush = lineShape->GetBrush();
|
|
|
|
wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
|
|
lineShape->SetPen(& dottedPen);
|
|
lineShape->SetBrush((wxBrush *) wxTRANSPARENT_BRUSH);
|
|
|
|
lineShape->SetPen(old_pen);
|
|
lineShape->SetBrush(old_brush);
|
|
#endif
|
|
}
|
|
|
|
GetEventHandler()->OnMoveLink(FALSE);
|
|
|
|
|
|
if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM || lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
|
|
{
|
|
// lpt->SetX(x); lpt->SetY(y);
|
|
}
|
|
|
|
if (GetCanvas())
|
|
GetCanvas()->Refresh();
|
|
|
|
}
|
|
|
|
void wxLineShape::OnSizingBeginDragLeft(wxControlPoint *pt, double x, double y, int WXUNUSED(keys), int WXUNUSED(attachment))
|
|
{
|
|
wxLineControlPoint *lpt = (wxLineControlPoint *) pt;
|
|
|
|
#if 0
|
|
wxClientDC dc(GetCanvas());
|
|
GetCanvas()->PrepareDC(dc);
|
|
#endif
|
|
|
|
wxLineShape *lineShape = (wxLineShape *)this;
|
|
if (lpt->m_type == CONTROL_POINT_LINE)
|
|
{
|
|
lpt->m_originalPos = * (lpt->m_point);
|
|
m_canvas->Snap(&x, &y);
|
|
#if 0
|
|
this->Erase();
|
|
|
|
// Redraw start and end objects because we've left holes
|
|
// when erasing the line
|
|
lineShape->GetFrom()->OnDraw(dc);
|
|
lineShape->GetFrom()->OnDrawContents(dc);
|
|
lineShape->GetTo()->OnDraw(dc);
|
|
lineShape->GetTo()->OnDrawContents(dc);
|
|
|
|
this->SetDisableLabel(TRUE);
|
|
dc.SetLogicalFunction(OGLRBLF);
|
|
#endif
|
|
|
|
lpt->m_xpos = x;
|
|
lpt->m_ypos = y;
|
|
lpt->m_point->x = x;
|
|
lpt->m_point->y = y;
|
|
|
|
#if 0
|
|
wxPen *old_pen = lineShape->GetPen();
|
|
wxBrush *old_brush = lineShape->GetBrush();
|
|
|
|
wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
|
|
lineShape->SetPen(& dottedPen);
|
|
lineShape->SetBrush((wxBrush *) wxTRANSPARENT_BRUSH);
|
|
#endif
|
|
|
|
lineShape->GetEventHandler()->OnMoveLink(FALSE);
|
|
|
|
#if 0
|
|
lineShape->SetPen(old_pen);
|
|
lineShape->SetBrush(old_brush);
|
|
#endif
|
|
}
|
|
|
|
if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM || lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
|
|
{
|
|
m_canvas->SetCursor(wxCursor(wxCURSOR_BULLSEYE));
|
|
lpt->m_oldCursor = (wxCursor *) wxSTANDARD_CURSOR;
|
|
}
|
|
if (GetCanvas())
|
|
GetCanvas()->Refresh();
|
|
}
|
|
|
|
void wxLineShape::OnSizingEndDragLeft(wxControlPoint *pt, double x, double y, int WXUNUSED(keys), int WXUNUSED(attachment))
|
|
{
|
|
wxLineControlPoint *lpt = (wxLineControlPoint *) pt;
|
|
|
|
#if 0
|
|
wxClientDC dc(GetCanvas());
|
|
GetCanvas()->PrepareDC(dc);
|
|
#endif
|
|
|
|
this->SetDisableLabel(FALSE);
|
|
wxLineShape *lineShape = (wxLineShape *)this;
|
|
|
|
if (lpt->m_type == CONTROL_POINT_LINE)
|
|
{
|
|
m_canvas->Snap(&x, &y);
|
|
|
|
wxRealPoint pt = wxRealPoint(x, y);
|
|
|
|
// Move the control point back to where it was;
|
|
// MoveControlPoint will move it to the new position
|
|
// if it decides it wants. We only moved the position
|
|
// during user feedback so we could redraw the line
|
|
// as it changed shape.
|
|
lpt->m_xpos = lpt->m_originalPos.x;
|
|
lpt->m_ypos = lpt->m_originalPos.y;
|
|
lpt->m_point->x = lpt->m_originalPos.x;
|
|
lpt->m_point->y = lpt->m_originalPos.y;
|
|
|
|
OnMoveMiddleControlPoint(lpt, pt);
|
|
}
|
|
if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM)
|
|
{
|
|
if (lpt->m_oldCursor)
|
|
m_canvas->SetCursor(* lpt->m_oldCursor);
|
|
|
|
// this->Erase(dc);
|
|
|
|
// lpt->m_xpos = x; lpt->m_ypos = y;
|
|
|
|
if (lineShape->GetFrom())
|
|
{
|
|
lineShape->GetFrom()->MoveLineToNewAttachment(lineShape, x, y);
|
|
}
|
|
}
|
|
if (lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
|
|
{
|
|
if (lpt->m_oldCursor)
|
|
m_canvas->SetCursor(* lpt->m_oldCursor);
|
|
|
|
// lpt->m_xpos = x; lpt->m_ypos = y;
|
|
|
|
if (lineShape->GetTo())
|
|
{
|
|
lineShape->GetTo()->MoveLineToNewAttachment(lineShape, x, y);
|
|
}
|
|
}
|
|
|
|
// Needed?
|
|
#if 0
|
|
int i = 0;
|
|
for (i = 0; i < lineShape->GetLineControlPoints()->GetCount(); i++)
|
|
if (((wxRealPoint *)(lineShape->GetLineControlPoints()->Item(i)->GetData())) == lpt->m_point)
|
|
break;
|
|
|
|
// N.B. in OnMoveControlPoint, an event handler in Hardy could have deselected
|
|
// the line and therefore deleted 'this'. -> GPF, intermittently.
|
|
// So assume at this point that we've been blown away.
|
|
|
|
lineShape->OnMoveControlPoint(i + 1, x, y);
|
|
#endif
|
|
|
|
if (GetCanvas())
|
|
GetCanvas()->Refresh();
|
|
|
|
}
|
|
|
|
// This is called only when a non-end control point is moved.
|
|
bool wxLineShape::OnMoveMiddleControlPoint(wxLineControlPoint *lpt, const wxRealPoint &pt)
|
|
{
|
|
lpt->m_xpos = pt.x;
|
|
lpt->m_ypos = pt.y;
|
|
lpt->m_point->x = pt.x;
|
|
lpt->m_point->y = pt.y;
|
|
|
|
GetEventHandler()->OnMoveLink();
|
|
|
|
if (GetCanvas())
|
|
GetCanvas()->Refresh();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Implement movement of endpoint to a new attachment
|
|
// OBSOLETE: done by dragging with the left button.
|
|
|
|
#if 0
|
|
void wxLineControlPoint::OnDragRight(bool draw, double x, double y, int keys, int attachment)
|
|
{
|
|
if (m_type == CONTROL_POINT_ENDPOINT_FROM || m_type == CONTROL_POINT_ENDPOINT_TO)
|
|
{
|
|
m_xpos = x;
|
|
m_ypos = y;
|
|
}
|
|
}
|
|
|
|
void wxLineControlPoint::OnBeginDragRight(double x, double y, int keys, int attachment)
|
|
{
|
|
wxLineShape *lineShape = (wxLineShape *)m_shape;
|
|
if (m_type == CONTROL_POINT_ENDPOINT_FROM || m_type == CONTROL_POINT_ENDPOINT_TO)
|
|
{
|
|
lineShape->GetEventHandler()->OnDraw(dc);
|
|
if (m_type == CONTROL_POINT_ENDPOINT_FROM)
|
|
{
|
|
lineShape->GetFrom()->GetEventHandler()->OnDraw(dc);
|
|
lineShape->GetFrom()->GetEventHandler()->OnDrawContents(dc);
|
|
}
|
|
else
|
|
{
|
|
lineShape->GetTo()->GetEventHandler()->OnDraw(dc);
|
|
lineShape->GetTo()->GetEventHandler()->OnDrawContents(dc);
|
|
}
|
|
m_canvas->SetCursor(wxCursor(wxCURSOR_BULLSEYE));
|
|
m_oldCursor = wxSTANDARD_CURSOR;
|
|
}
|
|
|
|
if (GetCanvas())
|
|
GetCanvas()->Refresh();
|
|
}
|
|
|
|
void wxLineControlPoint::OnEndDragRight(double x, double y, int keys, int attachment)
|
|
{
|
|
wxLineShape *lineShape = (wxLineShape *)m_shape;
|
|
if (m_type == CONTROL_POINT_ENDPOINT_FROM)
|
|
{
|
|
if (m_oldCursor)
|
|
m_canvas->SetCursor(m_oldCursor);
|
|
|
|
m_xpos = x;
|
|
m_ypos = y;
|
|
|
|
if (lineShape->GetFrom())
|
|
{
|
|
int new_attachment;
|
|
double distance;
|
|
|
|
if (lineShape->GetFrom()->HitTest(x, y, &new_attachment, &distance))
|
|
lineShape->SetAttachments(new_attachment, lineShape->GetAttachmentTo());
|
|
|
|
lineShape->GetFrom()->MoveLinks();
|
|
}
|
|
}
|
|
if (m_type == CONTROL_POINT_ENDPOINT_TO)
|
|
{
|
|
if (m_oldCursor)
|
|
m_canvas->SetCursor(m_oldCursor);
|
|
m_shape->Erase(dc);
|
|
|
|
m_xpos = x;
|
|
m_ypos = y;
|
|
|
|
if (lineShape->GetTo())
|
|
{
|
|
int new_attachment;
|
|
double distance;
|
|
if (lineShape->GetTo()->HitTest(x, y, &new_attachment, &distance))
|
|
lineShape->SetAttachments(lineShape->GetAttachmentFrom(), new_attachment);
|
|
|
|
lineShape->GetTo()->MoveLinks();
|
|
}
|
|
}
|
|
int i = 0;
|
|
for (i = 0; i < lineShape->GetLineControlPoints()->GetCount(); i++)
|
|
if (((wxRealPoint *)(lineShape->GetLineControlPoints()->Item(i)->GetData())) == m_point)
|
|
break;
|
|
lineShape->OnMoveControlPoint(i + 1, x, y);
|
|
if (GetCanvas())
|
|
GetCanvas()->Refresh();
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Get the point on the given line (x1, y1) (x2, y2)
|
|
* distance 'length' along from the end,
|
|
* returned values in x and y
|
|
*/
|
|
|
|
void GetPointOnLine(double x1, double y1, double x2, double y2,
|
|
double length, double *x, double *y)
|
|
{
|
|
double l = (double)sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
|
|
|
if (l < 0.01)
|
|
l = (double) 0.01;
|
|
|
|
double i_bar = (x2 - x1) / l;
|
|
double j_bar = (y2 - y1) / l;
|
|
|
|
*x = (- length * i_bar) + x2;
|
|
*y = (- length * j_bar) + y2;
|
|
}
|
|
|
|
wxArrowHead *wxLineShape::AddArrow(WXTYPE type, int end, double size, double xOffset,
|
|
const wxString &name, wxPseudoMetaFile *mf, long arrowId)
|
|
{
|
|
wxArrowHead *arrow = new wxArrowHead(type, end, size, xOffset, name, mf, arrowId);
|
|
m_arcArrows.Append(arrow);
|
|
return arrow;
|
|
}
|
|
|
|
/*
|
|
* Add arrowhead at a particular position in the arrowhead list.
|
|
*/
|
|
bool wxLineShape::AddArrowOrdered(wxArrowHead *arrow, wxList &referenceList, int end)
|
|
{
|
|
wxNode *refNode = referenceList.GetFirst();
|
|
wxNode *currNode = m_arcArrows.GetFirst();
|
|
wxString targetName(arrow->GetName());
|
|
if (!refNode) return FALSE;
|
|
|
|
// First check whether we need to insert in front of list,
|
|
// because this arrowhead is the first in the reference
|
|
// list and should therefore be first in the current list.
|
|
wxArrowHead *refArrow = (wxArrowHead *)refNode->GetData();
|
|
if (refArrow->GetName() == targetName)
|
|
{
|
|
m_arcArrows.Insert(arrow);
|
|
return TRUE;
|
|
}
|
|
|
|
wxArrowHead *currArrow = (wxArrowHead *)currNode->GetData();
|
|
while (refNode && currNode)
|
|
{
|
|
refArrow = (wxArrowHead *)refNode->GetData();
|
|
|
|
// Matching: advance current arrow pointer
|
|
if ((currArrow->GetArrowEnd() == end) &&
|
|
(currArrow->GetName() == refArrow->GetName()))
|
|
{
|
|
currNode = currNode->GetNext(); // Could be NULL now
|
|
if (currNode)
|
|
currArrow = (wxArrowHead *)currNode->GetData();
|
|
}
|
|
|
|
// Check if we're at the correct position in the
|
|
// reference list
|
|
if (targetName == refArrow->GetName())
|
|
{
|
|
if (currNode)
|
|
m_arcArrows.Insert(currNode, arrow);
|
|
else
|
|
m_arcArrows.Append(arrow);
|
|
return TRUE;
|
|
}
|
|
refNode = refNode->GetNext();
|
|
}
|
|
m_arcArrows.Append(arrow);
|
|
return TRUE;
|
|
}
|
|
|
|
void wxLineShape::ClearArrowsAtPosition(int end)
|
|
{
|
|
wxNode *node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrow = (wxArrowHead *)node->GetData();
|
|
wxNode *next = node->GetNext();
|
|
switch (end)
|
|
{
|
|
case -1:
|
|
{
|
|
delete arrow;
|
|
delete node;
|
|
break;
|
|
}
|
|
case ARROW_POSITION_START:
|
|
{
|
|
if (arrow->GetArrowEnd() == ARROW_POSITION_START)
|
|
{
|
|
delete arrow;
|
|
delete node;
|
|
}
|
|
break;
|
|
}
|
|
case ARROW_POSITION_END:
|
|
{
|
|
if (arrow->GetArrowEnd() == ARROW_POSITION_END)
|
|
{
|
|
delete arrow;
|
|
delete node;
|
|
}
|
|
break;
|
|
}
|
|
case ARROW_POSITION_MIDDLE:
|
|
{
|
|
if (arrow->GetArrowEnd() == ARROW_POSITION_MIDDLE)
|
|
{
|
|
delete arrow;
|
|
delete node;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
node = next;
|
|
}
|
|
}
|
|
|
|
bool wxLineShape::ClearArrow(const wxString &name)
|
|
{
|
|
wxNode *node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrow = (wxArrowHead *)node->GetData();
|
|
if (arrow->GetName() == name)
|
|
{
|
|
delete arrow;
|
|
delete node;
|
|
return TRUE;
|
|
}
|
|
node = node->GetNext();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Finds an arrowhead at the given position (if -1, any position)
|
|
*
|
|
*/
|
|
|
|
wxArrowHead *wxLineShape::FindArrowHead(int position, const wxString &name)
|
|
{
|
|
wxNode *node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrow = (wxArrowHead *)node->GetData();
|
|
if (((position == -1) || (position == arrow->GetArrowEnd())) &&
|
|
(arrow->GetName() == name))
|
|
return arrow;
|
|
node = node->GetNext();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
wxArrowHead *wxLineShape::FindArrowHead(long arrowId)
|
|
{
|
|
wxNode *node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrow = (wxArrowHead *)node->GetData();
|
|
if (arrowId == arrow->GetId())
|
|
return arrow;
|
|
node = node->GetNext();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Deletes an arrowhead at the given position (if -1, any position)
|
|
*
|
|
*/
|
|
|
|
bool wxLineShape::DeleteArrowHead(int position, const wxString &name)
|
|
{
|
|
wxNode *node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrow = (wxArrowHead *)node->GetData();
|
|
if (((position == -1) || (position == arrow->GetArrowEnd())) &&
|
|
(arrow->GetName() == name))
|
|
{
|
|
delete arrow;
|
|
delete node;
|
|
return TRUE;
|
|
}
|
|
node = node->GetNext();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Overloaded DeleteArrowHead: pass arrowhead id.
|
|
bool wxLineShape::DeleteArrowHead(long id)
|
|
{
|
|
wxNode *node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrow = (wxArrowHead *)node->GetData();
|
|
if (arrow->GetId() == id)
|
|
{
|
|
delete arrow;
|
|
delete node;
|
|
return TRUE;
|
|
}
|
|
node = node->GetNext();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Calculate the minimum width a line
|
|
* occupies, for the purposes of drawing lines in tools.
|
|
*
|
|
*/
|
|
|
|
double wxLineShape::FindMinimumWidth()
|
|
{
|
|
double minWidth = 0.0;
|
|
wxNode *node = m_arcArrows.GetFirst();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrowHead = (wxArrowHead *)node->GetData();
|
|
minWidth += arrowHead->GetSize();
|
|
if (node->GetNext())
|
|
minWidth += arrowHead->GetSpacing();
|
|
|
|
node = node->GetNext();
|
|
}
|
|
// We have ABSOLUTE minimum now. So
|
|
// scale it to give it reasonable aesthetics
|
|
// when drawing with line.
|
|
if (minWidth > 0.0)
|
|
minWidth = (double)(minWidth * 1.4);
|
|
else
|
|
minWidth = 20.0;
|
|
|
|
SetEnds(0.0, 0.0, minWidth, 0.0);
|
|
Initialise();
|
|
|
|
return minWidth;
|
|
}
|
|
|
|
// Find which position we're talking about at this (x, y).
|
|
// Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END
|
|
int wxLineShape::FindLinePosition(double x, double y)
|
|
{
|
|
double startX, startY, endX, endY;
|
|
GetEnds(&startX, &startY, &endX, &endY);
|
|
|
|
// Find distances from centre, start and end. The smallest wins.
|
|
double centreDistance = (double)(sqrt((x - m_xpos) * (x - m_xpos) + (y - m_ypos) * (y - m_ypos)));
|
|
double startDistance = (double)(sqrt((x - startX) * (x - startX) + (y - startY) * (y - startY)));
|
|
double endDistance = (double)(sqrt((x - endX) * (x - endX) + (y - endY) * (y - endY)));
|
|
|
|
if (centreDistance < startDistance && centreDistance < endDistance)
|
|
return ARROW_POSITION_MIDDLE;
|
|
else if (startDistance < endDistance)
|
|
return ARROW_POSITION_START;
|
|
else
|
|
return ARROW_POSITION_END;
|
|
}
|
|
|
|
// Set alignment flags
|
|
void wxLineShape::SetAlignmentOrientation(bool isEnd, bool isHoriz)
|
|
{
|
|
if (isEnd)
|
|
{
|
|
if (isHoriz && ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) != LINE_ALIGNMENT_HORIZ))
|
|
m_alignmentEnd |= LINE_ALIGNMENT_HORIZ;
|
|
else if (!isHoriz && ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ))
|
|
m_alignmentEnd -= LINE_ALIGNMENT_HORIZ;
|
|
}
|
|
else
|
|
{
|
|
if (isHoriz && ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) != LINE_ALIGNMENT_HORIZ))
|
|
m_alignmentStart |= LINE_ALIGNMENT_HORIZ;
|
|
else if (!isHoriz && ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ))
|
|
m_alignmentStart -= LINE_ALIGNMENT_HORIZ;
|
|
}
|
|
}
|
|
|
|
void wxLineShape::SetAlignmentType(bool isEnd, int alignType)
|
|
{
|
|
if (isEnd)
|
|
{
|
|
if (alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE)
|
|
{
|
|
if ((m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE) != LINE_ALIGNMENT_TO_NEXT_HANDLE)
|
|
m_alignmentEnd |= LINE_ALIGNMENT_TO_NEXT_HANDLE;
|
|
}
|
|
else if ((m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE) == LINE_ALIGNMENT_TO_NEXT_HANDLE)
|
|
m_alignmentEnd -= LINE_ALIGNMENT_TO_NEXT_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
if (alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE)
|
|
{
|
|
if ((m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE) != LINE_ALIGNMENT_TO_NEXT_HANDLE)
|
|
m_alignmentStart |= LINE_ALIGNMENT_TO_NEXT_HANDLE;
|
|
}
|
|
else if ((m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE) == LINE_ALIGNMENT_TO_NEXT_HANDLE)
|
|
m_alignmentStart -= LINE_ALIGNMENT_TO_NEXT_HANDLE;
|
|
}
|
|
}
|
|
|
|
bool wxLineShape::GetAlignmentOrientation(bool isEnd)
|
|
{
|
|
if (isEnd)
|
|
return ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ);
|
|
else
|
|
return ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ);
|
|
}
|
|
|
|
int wxLineShape::GetAlignmentType(bool isEnd)
|
|
{
|
|
if (isEnd)
|
|
return (m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE);
|
|
else
|
|
return (m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE);
|
|
}
|
|
|
|
wxRealPoint *wxLineShape::GetNextControlPoint(wxShape *nodeObject)
|
|
{
|
|
int n = m_lineControlPoints->GetCount();
|
|
int nn;
|
|
if (m_to == nodeObject)
|
|
{
|
|
// Must be END of line, so we want (n - 1)th control point.
|
|
// But indexing ends at n-1, so subtract 2.
|
|
nn = n - 2;
|
|
}
|
|
else nn = 1;
|
|
wxNode *node = m_lineControlPoints->Item(nn);
|
|
if (node)
|
|
{
|
|
return (wxRealPoint *)node->GetData();
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Arrowhead
|
|
*
|
|
*/
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxArrowHead, wxObject)
|
|
|
|
wxArrowHead::wxArrowHead(WXTYPE type, int end, double size, double dist, const wxString &name,
|
|
wxPseudoMetaFile *mf, long arrowId)
|
|
{
|
|
m_arrowType = type;
|
|
m_arrowEnd = end;
|
|
m_arrowSize = size;
|
|
m_xOffset = dist;
|
|
m_yOffset = 0.0;
|
|
m_spacing = 5.0;
|
|
|
|
m_arrowName = name;
|
|
m_metaFile = mf;
|
|
m_id = arrowId;
|
|
if (m_id == -1)
|
|
m_id = wxNewId();
|
|
}
|
|
|
|
wxArrowHead::wxArrowHead(wxArrowHead &toCopy)
|
|
{
|
|
m_arrowType = toCopy.m_arrowType;
|
|
m_arrowEnd = toCopy.GetArrowEnd();
|
|
m_arrowSize = toCopy.m_arrowSize;
|
|
m_xOffset = toCopy.m_xOffset;
|
|
m_yOffset = toCopy.m_yOffset;
|
|
m_spacing = toCopy.m_spacing;
|
|
m_arrowName = toCopy.m_arrowName ;
|
|
if (toCopy.m_metaFile)
|
|
m_metaFile = new wxPseudoMetaFile(*(toCopy.m_metaFile));
|
|
else
|
|
m_metaFile = NULL;
|
|
m_id = wxNewId();
|
|
}
|
|
|
|
wxArrowHead::~wxArrowHead()
|
|
{
|
|
if (m_metaFile) delete m_metaFile;
|
|
}
|
|
|
|
void wxArrowHead::SetSize(double size)
|
|
{
|
|
m_arrowSize = size;
|
|
if ((m_arrowType == ARROW_METAFILE) && m_metaFile)
|
|
{
|
|
double oldWidth = m_metaFile->m_width;
|
|
if (oldWidth == 0.0)
|
|
return;
|
|
|
|
double scale = (double)(size / oldWidth);
|
|
if (scale != 1.0)
|
|
m_metaFile->Scale(scale, scale);
|
|
}
|
|
}
|
|
|
|
// Can override this to create a different class of label shape
|
|
wxLabelShape *wxLineShape::OnCreateLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h)
|
|
{
|
|
return new wxLabelShape(parent, region, w, h);
|
|
}
|
|
|
|
/*
|
|
* Label object
|
|
*
|
|
*/
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxLabelShape, wxRectangleShape)
|
|
|
|
wxLabelShape::wxLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h): wxRectangleShape(w, h)
|
|
{
|
|
m_lineShape = parent;
|
|
m_shapeRegion = region;
|
|
SetPen(wxThePenList->FindOrCreatePen(wxColour(0, 0, 0), 1, wxPENSTYLE_DOT));
|
|
}
|
|
|
|
wxLabelShape::~wxLabelShape()
|
|
{
|
|
}
|
|
|
|
void wxLabelShape::OnDraw(wxDC &dc)
|
|
{
|
|
if (m_lineShape && !m_lineShape->GetDrawHandles())
|
|
return;
|
|
|
|
double x1 = (double)(m_xpos - m_width / 2.0);
|
|
double y1 = (double)(m_ypos - m_height / 2.0);
|
|
|
|
if (m_pen)
|
|
{
|
|
if (m_pen->GetWidth() == 0)
|
|
dc.SetPen(* g_oglTransparentPen);
|
|
else
|
|
dc.SetPen(* m_pen);
|
|
}
|
|
dc.SetBrush(* wxTRANSPARENT_BRUSH);
|
|
|
|
if (m_cornerRadius > 0.0)
|
|
dc.DrawRoundedRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
|
|
else
|
|
dc.DrawRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height));
|
|
}
|
|
|
|
void wxLabelShape::OnDrawContents(wxDC &WXUNUSED(dc))
|
|
{
|
|
}
|
|
|
|
void wxLabelShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
|
|
{
|
|
wxRectangleShape::OnDragLeft(draw, x, y, keys, attachment);
|
|
}
|
|
|
|
void wxLabelShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
|
|
{
|
|
wxRectangleShape::OnBeginDragLeft(x, y, keys, attachment);
|
|
}
|
|
|
|
void wxLabelShape::OnEndDragLeft(double x, double y, int keys, int attachment)
|
|
{
|
|
wxRectangleShape::OnEndDragLeft(x, y, keys, attachment);
|
|
}
|
|
|
|
bool wxLabelShape::OnMovePre(double x, double y, double old_x, double old_y, bool display)
|
|
{
|
|
return m_lineShape->OnLabelMovePre(this, x, y, old_x, old_y, display);
|
|
}
|
|
|
|
bool wxLineShape::OnLabelMovePre(wxLabelShape *labelShape, double x, double y, double WXUNUSED(old_x), double WXUNUSED(old_y), bool WXUNUSED(display))
|
|
{
|
|
labelShape->m_shapeRegion->SetSize(labelShape->GetWidth(), labelShape->GetHeight());
|
|
|
|
// Find position in line's region list
|
|
int i = 0;
|
|
wxNode *node = GetRegions().GetFirst();
|
|
while (node)
|
|
{
|
|
if (labelShape->m_shapeRegion == (wxShapeRegion *)node->GetData())
|
|
node = NULL;
|
|
else
|
|
{
|
|
node = node->GetNext();
|
|
i ++;
|
|
}
|
|
}
|
|
double xx, yy;
|
|
GetLabelPosition(i, &xx, &yy);
|
|
// Set the region's offset, relative to the default position for
|
|
// each region.
|
|
labelShape->m_shapeRegion->SetPosition((double)(x - xx), (double)(y - yy));
|
|
|
|
labelShape->SetX(x);
|
|
labelShape->SetY(y);
|
|
|
|
// Need to reformat to fit region.
|
|
if (!labelShape->m_shapeRegion->GetText().IsEmpty())
|
|
{
|
|
wxClientDC dc(GetCanvas());
|
|
GetCanvas()->PrepareDC(dc);
|
|
|
|
wxString s(labelShape->m_shapeRegion->GetText());
|
|
labelShape->FormatText(dc, s, i);
|
|
// DrawRegion(dc, labelShape->m_shapeRegion, xx, yy);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// Divert left and right clicks to line object
|
|
void wxLabelShape::OnLeftClick(double x, double y, int keys, int attachment)
|
|
{
|
|
m_lineShape->GetEventHandler()->OnLeftClick(x, y, keys, attachment);
|
|
}
|
|
|
|
void wxLabelShape::OnRightClick(double x, double y, int keys, int attachment)
|
|
{
|
|
m_lineShape->GetEventHandler()->OnRightClick(x, y, keys, attachment);
|
|
}
|
|
|