home *** CD-ROM | disk | FTP | other *** search
- /*
- * File: graphics.cc
- * Purpose: Object graphics library for wxWindows.
- * Defines a canvas which repaints its own graphics objects.
- *
- * wxWindows 1.40
- * Copyright (c) 1993 Artificial Intelligence Applications Institute,
- * The University of Edinburgh
- *
- * Author: Julian Smart
- * Date: 18-4-93
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose is hereby granted without fee, provided
- * that the above copyright notice, author statement and this permission
- * notice appear in all copies of this software and related documentation.
- *
- * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS,
- * IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL THE ARTIFICIAL INTELLIGENCE APPLICATIONS INSTITUTE OR THE
- * UNIVERSITY OF EDINBURGH BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF
- * DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH
- * THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
- #include <windows.h>
- #include <iostream.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <math.h>
- #include <wx.h>
- #include "graphics.h"
-
- wxFont *normal_font;
- wxFont *swiss_font_4;
- wxFont *swiss_font_6;
- wxFont *swiss_font_8;
- wxFont *swiss_font_10;
- wxFont *swiss_font_12;
- wxFont *swiss_font_14;
- wxFont *swiss_font_18;
- wxFont *swiss_font_24;
-
- wxFont *italic_font;
- wxPen *red_pen;
- wxPen *cyan_pen;
- wxPen *green_pen;
- wxPen *black_pen;
-
- wxBrush *blue_brush;
- wxBrush *green_brush;
- wxBrush *white_brush;
- wxBrush *black_brush;
- wxBrush *cyan_brush;
- wxBrush *red_brush;
-
- wxPen *white_background_pen;
- wxBrush *transparent_brush;
- wxBrush *white_background_brush;
- wxPen *black_foreground_pen;
- wxPen *black_dashed_pen;
-
- wxCursor *GraphicsBullseyeCursor = NULL;
-
- void GraphicsInitialize(void)
- {
- GraphicsBullseyeCursor = new wxCursor(wxCURSOR_BULLSEYE);
-
- normal_font = new wxFont(12, wxMODERN, wxNORMAL, wxNORMAL);
- italic_font = new wxFont(12, wxROMAN, wxITALIC, wxNORMAL);
-
- swiss_font_4 = new wxFont(4, wxSWISS, wxNORMAL, wxNORMAL);
- swiss_font_6 = new wxFont(6, wxSWISS, wxNORMAL, wxNORMAL);
- swiss_font_8 = new wxFont(8, wxSWISS, wxNORMAL, wxNORMAL);
- swiss_font_10 = new wxFont(10, wxSWISS, wxNORMAL, wxNORMAL);
- swiss_font_12 = new wxFont(12, wxSWISS, wxNORMAL, wxNORMAL);
- swiss_font_14 = new wxFont(14, wxSWISS, wxNORMAL, wxNORMAL);
- swiss_font_18 = new wxFont(18, wxSWISS, wxNORMAL, wxNORMAL);
- swiss_font_24 = new wxFont(24, wxSWISS, wxNORMAL, wxNORMAL);
-
- red_pen = new wxPen("RED", 3, wxSOLID);
- cyan_pen = new wxPen("CYAN", 3, wxSOLID);
- green_pen = new wxPen("GREEN", 1, wxSOLID);
- black_pen = new wxPen("BLACK", 1, wxSOLID);
-
- blue_brush = new wxBrush("BLUE", wxSOLID);
- green_brush = new wxBrush("GREEN", wxSOLID);
- white_brush = new wxBrush("WHITE", wxSOLID);
- black_brush = new wxBrush("BLACK", wxSOLID);
- cyan_brush = new wxBrush("CYAN", wxSOLID);
- red_brush = new wxBrush("RED", wxSOLID);
-
- white_background_pen = new wxPen("WHITE", 4, wxSOLID);
- transparent_brush = new wxBrush("BLACK", wxTRANSPARENT);
- white_background_brush = new wxBrush("WHITE", wxSOLID);
- black_foreground_pen = new wxPen("BLACK", 1, wxSOLID);
- black_dashed_pen = new wxPen("BLACK", 1, wxSHORT_DASH);
- }
-
- wxFont *MatchFont(int point_size)
- {
- wxFont *font;
- switch (point_size)
- {
- case 4:
- font = swiss_font_4;
- break;
- case 6:
- font = swiss_font_6;
- break;
- case 8:
- font = swiss_font_8;
- break;
- case 12:
- font = swiss_font_12;
- break;
- case 14:
- font = swiss_font_14;
- break;
- case 18:
- font = swiss_font_18;
- break;
- case 24:
- font = swiss_font_24;
- break;
- default:
- case 10:
- font = swiss_font_10;
- break;
- }
- return font;
- }
-
- wxFont *FontSizeDialog(wxFrame *parent)
- {
- char *strings[] = { "4", "6", "8", "10", "12", "14", "18", "24" };
- char *ans = wxGetSingleChoice("Choose", "Choose a font size", 8, strings, parent);
- if (ans)
- {
- int size = atoi(ans);
- return MatchFont(size);
- }
- else return NULL;
- }
-
- CanvasObjectTextLine::CanvasObjectTextLine(float the_x, float the_y, char *the_line)
- {
- x = the_x; y = the_y; line = copystring(the_line);
- }
-
- CanvasObjectTextLine::~CanvasObjectTextLine(void)
- {
- if (line) delete line;
- }
-
- CanvasObject::CanvasObject(void)
- {
- formatted = FALSE;
- canvas = NULL;
- dc = NULL;
- xpos = 0.0; ypos = 0.0;
- draggable = TRUE;
- pen = NULL; brush = NULL; font = NULL; text_colour = wxBLACK;
- visible = FALSE;
- ClientData = NULL;
- selected = FALSE;
- attachment_mode = FALSE;
- disable_label = FALSE;
- }
-
- CanvasObject::CanvasObject(ObjectCanvas *can)
- {
- text.DeleteContents(TRUE); // List will delete contents when deleted
- formatted = FALSE;
- canvas = can;
- xpos = 0.0; ypos = 0.0;
- draggable = TRUE;
- pen = NULL; brush = NULL; font = NULL; text_colour = NULL;
- visible = FALSE;
- ClientData = NULL;
- selected = FALSE;
- disable_label = FALSE;
- }
-
- CanvasObject::~CanvasObject(void)
- {
- ClearText();
-
- if (canvas)
- {
- canvas->RemoveObject(this);
- }
-
- }
-
- void CanvasObject::SetClientData(wxObject *client_data)
- {
- ClientData = client_data;
- }
-
- wxObject *CanvasObject::GetClientData(void)
- {
- return ClientData;
- }
-
- void CanvasObject::SetDC(wxDC *the_dc)
- {
- dc = the_dc;
- }
-
- void CanvasObject::ClearText(void)
- {
- text.Clear();
- }
-
- Bool CanvasObject::HitTest(float x, float y, int *attachment, float *distance)
- {
- float width = 0.0, height = 0.0;
- GetBoundingBox(&width, &height);
- if (fabs(width) < 4.0) width = 4.0;
- if (fabs(height) < 4.0) height = 4.0;
-
- width += (float)4.0; height += (float)4.0; // Allowance for inaccurate mousing
-
- float left = (float)(xpos - (width/2.0));
- float top = (float)(ypos - (height/2.0));
- float right = (float)(xpos + (width/2.0));
- float bottom = (float)(ypos + (height/2.0));
-
- int nearest_attachment = 0;
-
-
- // If within the bounding box, check the attachment points
- // within the object.
-
- if (x >= left && x <= right && y >= top && y <= bottom)
- {
- int n = GetNumberOfAttachments();
- float nearest = 999999.0;
-
- for (int i = 0; i < n; i++)
- {
- float xpos, ypos;
- GetAttachmentPosition(i, &xpos, &ypos);
-
- float l = (float)sqrt(((xpos - x) * (xpos - x)) +
- ((ypos - y) * (ypos - y)));
-
- if (l < nearest)
- {
- nearest = l;
- nearest_attachment = i;
- }
- }
- *attachment = nearest_attachment;
- *distance = nearest;
- return TRUE;
- }
- else return FALSE;
- }
-
- // Format a text string according to the bounding box, add
- // strings to text list
- void CanvasObject::FormatText(char *s)
- {
- if (!dc)
- return;
-
- float w, h;
- ClearText();
- dc->SetFont(font);
-
- GetBoundingBox(&w, &h);
-
- wxList *string_list = ::FormatText(dc, s, (w-5), (h-5));
- wxNode *node = string_list->First();
- while (node)
- {
- char *s = (char *)node->Data();
- CanvasObjectTextLine *line = new CanvasObjectTextLine(0.0, 0.0, s);
- text.Append((wxObject *)line);
- delete node;
- node = string_list->First();
- }
- delete string_list;
- CentreText(dc, &text, xpos, ypos, w, h);
- formatted = TRUE;
- }
-
- void CanvasObject::GetBoundingBox(float *width, float *height)
- {
- }
-
- Bool CanvasObject::GetPerimeterPoint(float x1, float y1,
- float x2, float y2,
- float *x3, float *y3)
- {
- return FALSE;
- }
-
- float CanvasObject::GetX(void)
- {
- return xpos;
- }
-
- float CanvasObject::GetY(void)
- {
- return ypos;
- }
-
- void CanvasObject::SetPen(wxPen *the_pen)
- {
- pen = the_pen;
- }
-
- void CanvasObject::SetBrush(wxBrush *the_brush)
- {
- brush = the_brush;
- }
-
- void CanvasObject::SetFont(wxFont *the_font)
- {
- font = the_font;
- }
-
- void CanvasObject::OnDraw(void)
- {
- }
-
- void CanvasObject::OnMoveLinks(void)
- {
- // Want to set the ends of all attached links
- // to point to/from this object
-
- wxNode *current = lines.First();
- while (current)
- {
- LineObject *line = (LineObject *)current->Data();
- line->OnMoveLink();
- current = current->Next();
- }
- }
-
-
- void CanvasObject::OnDrawContents(void)
- {
- float bound_x, bound_y;
- GetBoundingBox(&bound_x, &bound_y);
- if (dc)
- {
- if (font) dc->SetFont(font);
- if (pen) dc->SetPen(pen);
-
- if (text_colour) dc->SetTextForeground(text_colour);
- #ifdef wx_msw
- // For efficiency, don't do this under X - doesn't make
- // any visible difference for our purposes.
- if (brush && brush->colour)
- dc->SetTextBackground(brush->colour);
- #endif
-
- if (!formatted)
- {
- CentreText(dc, &text, xpos, ypos, bound_x, bound_y);
- formatted = TRUE;
- }
- if (!disable_label)
- DrawFormattedText(dc, &text, xpos, ypos, bound_x, bound_y);
- }
- }
-
- void CanvasObject::DrawContents(void)
- {
- OnDrawContents();
- }
-
- void CanvasObject::OnSize(float x, float y)
- {
- }
-
- void CanvasObject::OnMove(float x, float y, float old_x, float old_y)
- {
- // Draw();
- }
-
- void CanvasObject::OnErase(void)
- {
- if (!visible)
- return;
-
- // Erase links
- wxNode *current = lines.First();
- while (current)
- {
- LineObject *line = (LineObject *)current->Data();
- line->OnErase();
- current = current->Next();
- }
-
- float bound_x, bound_y;
- GetBoundingBox(&bound_x, &bound_y);
-
- if (dc)
- {
- dc->SetPen(white_background_pen);
- dc->SetBrush(white_background_brush);
- dc->DrawRectangle(
- (float)(xpos - bound_x/2.0), (float)(ypos - bound_y/2.0),
- (float)bound_x, (float)bound_y);
- }
- }
-
- void CanvasObject::EraseLinks(int attachment)
- {
- if (!visible)
- return;
-
- wxNode *current = lines.First();
- while (current)
- {
- LineObject *line = (LineObject *)current->Data();
- if (attachment == -1 || ((line->to == this && line->attachment_to == attachment) ||
- (line->from == this && line->attachment_from == attachment)))
- line->OnErase();
- current = current->Next();
- }
- }
-
- void CanvasObject::DrawLinks(int attachment)
- {
- if (!visible)
- return;
-
- wxNode *current = lines.First();
- while (current)
- {
- LineObject *line = (LineObject *)current->Data();
- if (attachment == -1 ||
- (line->to == this && line->attachment_to == attachment) ||
- (line->from == this && line->attachment_from == attachment))
- line->Draw();
- current = current->Next();
- }
- }
-
- void CanvasObject::MoveLineToNewAttachment(LineObject *to_move,
- float x, float y)
- {
- int new_point;
- float distance;
-
- // Is (x, y) on this object? If so, find the new attachment point
- // the user has moved the point to
- Bool hit = HitTest(x, y, &new_point, &distance);
- if (!hit)
- return;
-
- EraseLinks();
-
- int old_attachment;
- if (to_move->to == this)
- old_attachment = to_move->attachment_to;
- else
- old_attachment = to_move->attachment_from;
-
- // Delete the line object from the list of links; we're going to move
- // it to another position in the list
- lines.DeleteObject(to_move);
-
- float old_x = -9999.9;
- float old_y = -9999.9;
-
- wxNode *node = lines.First();
- Bool found = FALSE;
-
- while (node && !found)
- {
- LineObject *line = (LineObject *)node->Data();
- if ((line->to == this && old_attachment == line->attachment_to) ||
- (line->from == this && old_attachment == line->attachment_from))
- {
- float xp, yp;
- if (line->to == this)
- {
- xp = line->xpos2 + line->xpos;
- yp = line->ypos2 + line->ypos;
- } else
- {
- xp = line->xpos1 + line->xpos;
- yp = line->ypos1 + line->ypos;
- }
-
- switch (old_attachment)
- {
- case 0:
- case 2:
- {
- if (x > old_x && x <= xp)
- {
- found = TRUE;
- lines.Insert(node, to_move);
- }
- break;
- }
- case 1:
- case 3:
- {
- if (y > old_y && y <= yp)
- {
- found = TRUE;
- lines.Insert(node, to_move);
- }
- break;
- }
- }
- old_x = xp;
- old_y = yp;
- }
- node = node->Next();
- }
- if (!found)
- lines.Append(to_move);
-
-
- }
-
- void CanvasObject::OnHighlight(void)
- {
- }
-
- void CanvasObject::OnLeftClick(float x, float y, int keys, int attachment)
- {
- }
-
- void CanvasObject::OnRightClick(float x, float y, int keys, int attachment)
- {
- }
-
- void CanvasObject::OnDragLeft(Bool draw, float x, float y, int keys, int attachment)
- {
- canvas->Snap(&x, &y);
- xpos = x; ypos = y;
- OnDrawOutline();
- }
-
- void CanvasObject::OnBeginDragLeft(float x, float y, int keys, int attachment)
- {
- Erase();
- canvas->Snap(&x, &y);
- xpos = x; ypos = y;
- dc->SetLogicalFunction(wxXOR);
- OnDrawOutline();
- }
-
- void CanvasObject::OnEndDragLeft(float x, float y, int keys, int attachment)
- {
- dc->SetLogicalFunction(wxCOPY);
-
- canvas->Snap(&xpos, &ypos);
- Move(xpos, ypos);
- if (canvas && !canvas->quick_edit_mode) canvas->Redraw();
- }
-
- void CanvasObject::OnDragRight(Bool draw, float x, float y, int keys, int attachment)
- {
- }
-
- void CanvasObject::OnBeginDragRight(float x, float y, int keys, int attachment)
- {
- }
-
- void CanvasObject::OnEndDragRight(float x, float y, int keys, int attachment)
- {
- }
-
- void CanvasObject::OnDrawOutline(void)
- {
- float bound_x, bound_y;
- GetBoundingBox(&bound_x, &bound_y);
-
- dc->SetPen(black_dashed_pen);
- dc->SetBrush(transparent_brush);
-
- float top_left_x = (float)(xpos - bound_x/2.0);
- float top_left_y = (float)(ypos - bound_y/2.0);
- float top_right_x = (float)(xpos + bound_x/2.0);
- float top_right_y = (float)top_left_y;
- float bottom_left_x = (float)top_left_x;
- float bottom_left_y = (float)(ypos + bound_y/2.0);
- float bottom_right_x = (float)top_right_x;
- float bottom_right_y = (float)bottom_left_y;
-
- dc->DrawLine(top_left_x, top_left_y, top_right_x, top_right_y);
- dc->DrawLine(top_right_x, top_right_y, bottom_right_x, bottom_right_y);
- dc->DrawLine(bottom_right_x, bottom_right_y, bottom_left_x, bottom_left_y);
- dc->DrawLine(bottom_left_x, bottom_left_y, top_left_x, top_left_y);
- }
-
- void CanvasObject::Attach(ObjectCanvas *can)
- {
- canvas = can;
- }
-
- void CanvasObject::Detach(void)
- {
- canvas = NULL;
- }
-
- void CanvasObject::Draggable(Bool truth)
- {
- draggable = truth;
- }
-
- void CanvasObject::Move(float x, float y)
- {
- float old_x = xpos;
- float old_y = ypos;
-
- xpos = x; ypos = y;
-
- OnMove(x, y, old_x, old_y);
-
-
- ResetControlPoints();
-
- Draw();
-
- MoveLinks();
- OnDrawControlPoints();
- }
-
- void CanvasObject::MoveLinks(void)
- {
- OnMoveLinks();
- }
-
-
- void CanvasObject::Draw(void)
- {
- if (visible)
- {
- OnDraw();
- OnDrawContents();
- }
- }
-
- void CanvasObject::Flash(void)
- {
- if (dc)
- {
- dc->SetLogicalFunction(wxINVERT);
- Draw();
- dc->SetLogicalFunction(wxCOPY);
- Draw();
- }
- }
-
- void CanvasObject::Show(Bool show)
- {
- visible = show;
- }
-
- void CanvasObject::Erase(void)
- {
- OnErase();
- OnEraseControlPoints();
- }
-
- void CanvasObject::AddText(char *string)
- {
- text.Append(new CanvasObjectTextLine(0.0, 0.0, string));
- formatted = FALSE;
- }
-
- void CanvasObject::SetSize(float x, float y)
- {
- }
-
- // Add line FROM this object
- void CanvasObject::AddLine(LineObject *line, CanvasObject *other)
- {
- lines.Append(line);
- other->lines.Append(line);
- line->from = this;
- line->to = other;
- }
-
- void CanvasObject::RemoveLine(LineObject *line)
- {
- if (line->from == this)
- line->to->lines.DeleteObject(line);
- else
- line->from->lines.DeleteObject(line);
-
- lines.DeleteObject(line);
- }
-
- void CanvasObject::Copy(CanvasObject& copy)
- {
- copy.xpos = xpos;
- copy.ypos = ypos;
- copy.pen = pen;
- copy.brush = brush;
- copy.text_colour = text_colour;
-
- wxNode *node = text.First();
- while (node)
- {
- CanvasObjectTextLine *line = (CanvasObjectTextLine *)node->Data();
- CanvasObjectTextLine *new_line =
- new CanvasObjectTextLine(line->x, line->y, line->line);
- copy.text.Append(new_line);
- node = node->Next();
- }
- copy.draggable = draggable;
- copy.visible = visible;
- }
-
- // Default - make 6 control points
- void CanvasObject::MakeControlPoints(void)
- {
- float bound_x;
- float bound_y;
-
- GetBoundingBox(&bound_x, &bound_y);
-
- float new_width = (float)(bound_x*1.3);
- float new_height = (float)(bound_y*1.3);
-
- // Offsets from main object
- float top = (float)(- (new_height / 2.0));
- float bottom = (float)(new_height / 2.0);
- float left = (float)(- (new_width / 2.0));
- float right = (float)(new_width / 2.0);
-
- ControlPoint *control = new ControlPoint(canvas, this, CONTROL_POINT_SIZE, left, top,
- CONTROL_POINT_DIAGONAL);
- canvas->AddObject(control);
- control_points.Append(control);
-
- control = new ControlPoint(canvas, this, CONTROL_POINT_SIZE, 0, top,
- CONTROL_POINT_VERTICAL);
- canvas->AddObject(control);
- control_points.Append(control);
-
- control = new ControlPoint(canvas, this, CONTROL_POINT_SIZE, right, top,
- CONTROL_POINT_DIAGONAL);
- canvas->AddObject(control);
- control_points.Append(control);
-
- control = new ControlPoint(canvas, this, CONTROL_POINT_SIZE, right, 0,
- CONTROL_POINT_HORIZONTAL);
- canvas->AddObject(control);
- control_points.Append(control);
-
- control = new ControlPoint(canvas, this, CONTROL_POINT_SIZE, right, bottom,
- CONTROL_POINT_DIAGONAL);
- canvas->AddObject(control);
- control_points.Append(control);
-
- control = new ControlPoint(canvas, this, CONTROL_POINT_SIZE, 0, bottom,
- CONTROL_POINT_VERTICAL);
- canvas->AddObject(control);
- control_points.Append(control);
-
- control = new ControlPoint(canvas, this, CONTROL_POINT_SIZE, left, bottom,
- CONTROL_POINT_DIAGONAL);
- canvas->AddObject(control);
- control_points.Append(control);
-
- control = new ControlPoint(canvas, this, CONTROL_POINT_SIZE, left, 0,
- CONTROL_POINT_HORIZONTAL);
- canvas->AddObject(control);
- control_points.Append(control);
-
- }
-
- void CanvasObject::ResetControlPoints(void)
- {
- if (control_points.Number() < 1)
- return;
-
- float bound_x;
- float bound_y;
-
- GetBoundingBox(&bound_x, &bound_y);
-
- float new_width = (float)(bound_x*1.3);
- float new_height = (float)(bound_y*1.3);
-
- // Offsets from main object
- float top = (float)(- (new_height / 2.0));
- float bottom = (float)(new_height / 2.0);
- float left = (float)(- (new_width / 2.0));
- float right = (float)(new_width / 2.0);
-
- wxNode *node = control_points.First();
- ControlPoint *control = (ControlPoint *)node->Data();
- control->xoffset = left; control->yoffset = top;
-
- node = node->Next(); control = (ControlPoint *)node->Data();
- control->xoffset = 0; control->yoffset = top;
-
- node = node->Next(); control = (ControlPoint *)node->Data();
- control->xoffset = right; control->yoffset = top;
-
- node = node->Next(); control = (ControlPoint *)node->Data();
- control->xoffset = right; control->yoffset = 0;
-
- node = node->Next(); control = (ControlPoint *)node->Data();
- control->xoffset = right; control->yoffset = bottom;
-
- node = node->Next(); control = (ControlPoint *)node->Data();
- control->xoffset = 0; control->yoffset = bottom;
-
- node = node->Next(); control = (ControlPoint *)node->Data();
- control->xoffset = left; control->yoffset = bottom;
-
- node = node->Next(); control = (ControlPoint *)node->Data();
- control->xoffset = left; control->yoffset = 0;
- }
-
- void CanvasObject::DeleteControlPoints(void)
- {
- wxNode *node = control_points.First();
- while (node)
- {
- ControlPoint *control = (ControlPoint *)node->Data();
- control->OnErase();
- canvas->RemoveObject(control);
- delete control;
- delete node;
- node = control_points.First();
- }
- }
-
- void CanvasObject::OnDrawControlPoints(void)
- {
- wxNode *node = control_points.First();
- while (node)
- {
- ControlPoint *control = (ControlPoint *)node->Data();
- control->Draw();
- node = node->Next();
- }
- }
-
- void CanvasObject::OnEraseControlPoints(void)
- {
- wxNode *node = control_points.First();
- while (node)
- {
- ControlPoint *control = (ControlPoint *)node->Data();
- control->Erase();
- node = node->Next();
- }
- }
-
- void CanvasObject::Select(Bool select)
- {
- selected = select;
- if (select && (control_points.Number() == 0))
- {
- MakeControlPoints();
- OnDrawControlPoints();
- }
- if (!select && (control_points.Number() > 0))
- {
- DeleteControlPoints();
- }
- }
-
- Bool CanvasObject::Selected(void)
- {
- return selected;
- }
-
- int CanvasObject::GetNumberOfAttachments(void)
- {
- return 1;
- }
-
- void CanvasObject::GetAttachmentPosition(int attachment, float *x, float *y,
- int nth, int no_arcs)
- {
- *x = xpos; *y = ypos;
- }
-
- void CanvasObject::SetAttachmentMode(Bool flag)
- {
- attachment_mode = flag;
- }
-
- // Two stage construction: need to call Create
- PolygonObject::PolygonObject(void)
- {
- points = NULL;
- original_points = NULL;
- }
-
- void PolygonObject::Create(wxList *the_points)
- {
- original_points = the_points;
-
- // Duplicate the list of points
- points = new wxList;
-
- wxNode *node = the_points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- wxPoint *new_point = new wxPoint(point->x, point->y);
- points->Append(new_point);
- node = node->Next();
- }
- CalculateBoundingBox();
- original_width = bound_width;
- original_height = bound_height;
- }
-
- PolygonObject::~PolygonObject(void)
- {
- if (points)
- {
- wxNode *node = points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- delete point;
- delete node;
- node = points->First();
- }
- delete points;
- }
- if (original_points)
- {
- wxNode *node = original_points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- delete point;
- delete node;
- node = original_points->First();
- }
- delete original_points;
- }
- }
-
-
- // Width and height. Centre of object is centre of box.
- void PolygonObject::GetBoundingBox(float *width, float *height)
- {
- *width = bound_width;
- *height = bound_height;
- }
-
- void PolygonObject::CalculateBoundingBox(void)
- {
- // Calculate bounding box at construction (and presumably resize) time
- float left = 10000;
- float right = -10000;
- float top = 10000;
- float bottom = -10000;
-
- wxNode *node = points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- if (point->x < left) left = point->x;
- if (point->x > right) right = point->x;
-
- if (point->y < top) top = point->y;
- if (point->y > bottom) bottom = point->y;
-
- node = node->Next();
- }
- bound_width = right - left;
- bound_height = bottom - top;
- }
-
- // Really need to be able to reset the shape! Otherwise, if the
- // points ever go to zero, we've lost it, and can't resize.
- void PolygonObject::SetSize(float new_width, float new_height)
- {
- // Multiply all points by proportion of new size to old size
- float x_proportion = (float)(fabs(new_width/original_width));
- float y_proportion = (float)(fabs(new_height/original_height));
-
- wxNode *node = points->First();
- wxNode *original_node = original_points->First();
- while (node && original_node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- wxPoint *original_point = (wxPoint *)original_node->Data();
-
- point->x = (original_point->x * x_proportion);
- point->y = (original_point->y * y_proportion);
-
- node = node->Next();
- original_node = original_node->Next();
- }
-
- // CalculateBoundingBox();
- bound_width = (float)fabs(new_width);
- bound_height = (float)fabs(new_height);
- }
-
- // Assume (x1, y1) is centre of box (most generally, line end at box)
- Bool PolygonObject::GetPerimeterPoint(float x1, float y1,
- float x2, float y2,
- float *x3, float *y3)
- {
- int n = points->Number();
-
- float *xpoints = new float[n];
- float *ypoints = new float[n];
-
- wxNode *node = points->First();
- int i = 0;
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- xpoints[i] = point->x + xpos;
- ypoints[i] = point->y + ypos;
- node = node->Next();
- i ++;
- }
-
- find_end_for_polyline(n, xpoints, ypoints,
- x1, y1, x2, y2, x3, y3);
-
- delete xpoints;
- delete ypoints;
-
- return TRUE;
- }
-
- void PolygonObject::OnDraw(void)
- {
- if (dc)
- {
- if (pen)
- dc->SetPen(pen);
- if (brush)
- dc->SetBrush(brush);
- dc->DrawPolygon(points, xpos, ypos);
- }
- }
-
- void PolygonObject::Copy(PolygonObject& copy)
- {
- CanvasObject::Copy(copy);
-
- if (!copy.points)
- copy.points = new wxList;
-
- if (!copy.original_points)
- copy.original_points = new wxList;
-
- wxNode *node = points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- wxPoint *new_point = new wxPoint(point->x, point->y);
- copy.points->Append(new_point);
- node = node->Next();
- }
- node = original_points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- wxPoint *new_point = new wxPoint(point->x, point->y);
- copy.original_points->Append(new_point);
- node = node->Next();
- }
- copy.bound_width = bound_width;
- copy.bound_height = bound_height;
- copy.original_width = original_width;
- copy.original_height = original_height;
- }
-
- int PolygonObject::GetNumberOfAttachments(void)
- {
- if (points)
- return points->Number();
- else return 1;
- }
-
- void PolygonObject::GetAttachmentPosition(int attachment, float *x, float *y,
- int nth, int no_arcs)
- {
- if (attachment_mode && points && attachment < points->Number())
- {
- wxPoint *point = (wxPoint *)points->Nth(attachment)->Data();
- *x = point->x + xpos;
- *y = point->y + ypos;
- }
- else
- { *x = xpos; *y = ypos; }
- }
-
- // Rectangle object
-
- RectangleObject::RectangleObject(float w, float h)
- {
- width = w; height = h; corner_radius = 0.0;
- }
-
- void RectangleObject::OnDraw(void)
- {
- if (dc)
- {
- if (pen)
- dc->SetPen(pen);
- if (brush)
- dc->SetBrush(brush);
-
- float x1 = (float)(xpos - width/2.0);
- float y1 = (float)(ypos - height/2.0);
- if (corner_radius > 0.0)
- dc->DrawRoundedRectangle(x1, y1, width, height, corner_radius);
- else
- dc->DrawRectangle(x1, y1, width, height);
- }
- }
-
- void RectangleObject::GetBoundingBox(float *the_width, float *the_height)
- {
- *the_width = width;
- *the_height = height;
- }
-
- void RectangleObject::SetSize(float x, float y)
- {
- width = x;
- height = y;
- }
-
- void RectangleObject::SetCornerRadius(float rad)
- {
- corner_radius = rad;
- }
-
- // Assume (x1, y1) is centre of box (most generally, line end at box)
- Bool RectangleObject::GetPerimeterPoint(float x1, float y1,
- float x2, float y2,
- float *x3, float *y3)
- {
- float bound_x, bound_y;
- GetBoundingBox(&bound_x, &bound_y);
- find_end_for_box(bound_x, bound_y, xpos, ypos, x2, y2, x3, y3);
-
- return TRUE;
- }
-
- void RectangleObject::Copy(RectangleObject& copy)
- {
- CanvasObject::Copy(copy);
- copy.width = width;
- copy.height = height;
- copy.corner_radius = corner_radius;
- }
-
- int RectangleObject::GetNumberOfAttachments(void)
- {
- return 4;
- }
-
- // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
- // 3 = left.
- void RectangleObject::GetAttachmentPosition(int attachment, float *x, float *y,
- int nth, int no_arcs)
- {
- if (attachment_mode)
- {
- float top = (float)(ypos + height/2.0);
- float bottom = (float)(ypos - height/2.0);
- float left = (float)(xpos - width/2.0);
- float right = (float)(xpos + width/2.0);
- switch (attachment)
- {
- case 0:
- {
- *x = left + (nth + 1)*width/(no_arcs + 1);
- *y = bottom;
- break;
- }
- case 1:
- {
- *x = right;
- *y = bottom + (nth + 1)*height/(no_arcs + 1);
- break;
- }
- case 2:
- {
- *x = left + (nth + 1)*width/(no_arcs + 1);
- *y = top;
- break;
- }
- case 3:
- {
- *x = left;
- *y = bottom + (nth + 1)*height/(no_arcs + 1);
- break;
- }
- default:
- {
- *x = xpos; *y = ypos;
- break;
- }
- }
- }
- else
- { *x = xpos; *y = ypos; }
- }
-
- // Text object (no box)
-
- TextObject::TextObject(float width, float height):
- RectangleObject(width, height)
- {
- }
-
- void TextObject::OnDraw(void)
- {
- }
-
- // Ellipse object
-
- EllipseObject::EllipseObject(float w, float h)
- {
- width = w; height = h;
- }
-
- void EllipseObject::GetBoundingBox(float *w, float *h)
- {
- *w = width; *h = height;
- }
-
- Bool EllipseObject::GetPerimeterPoint(float x1, float y1,
- float x2, float y2,
- float *x3, float *y3)
- {
- float bound_x, bound_y;
- GetBoundingBox(&bound_x, &bound_y);
- find_end_for_box(bound_x, bound_y, xpos, ypos, x2, y2, x3, y3);
-
- /*
- float X2 = x2 - xpos;
- float Y2 = -(y2 - ypos);
-
- double a = 1/((width/2)*(width/2));
- double b = (Y2/X2)/((height/2)*(height/2));
- double c = -1;
-
- double X3a = (-b+sqrt(b*b - 4*a*c))/(2*a);
- double X3b = (-b-sqrt(b*b - 4*a*c))/(2*a);
-
- double Y3a = X3a*Y2/X2;
- double Y3b = X3b*Y2/X2;
-
- double x3a = X3a + xpos;
- double y3a = -Y3a + ypos;
-
- double x3b = X3b + xpos;
- double y3b = -Y3b + ypos;
-
- *x3 = (float)x3a;
- *y3 = (float)y3a;
-
- cout << "Ellipse: xpos = " << xpos << ", ypos = " << ypos << "; X2 = " << X2 << ", Y2 = "
- << Y2 << "\na = " << a << ", b = " << b << ", c = " << c << "\n";
- cout << "width = " << width << ", height = " << height << "\n";
- cout << "X3a = " << X3a << ", Y3a = " << Y3a << "\n";
- cout << "X3b = " << X3b << ", Y3b = " << Y3b << "\n";
- cout << "x3 = " << *x3 << ", y3 = " <<
- *y3 << "\n";
-
- ObjectCanvas *canvas = GetCanvas();
- dc->DrawLine(x3a - 10, y3a, x3a + 10, y3a);
- dc->DrawLine(x3b - 10, y3b, x3b + 10, y3b);
- */
- return TRUE;
- }
-
- void EllipseObject::OnDraw(void)
- {
- if (dc)
- {
- if (pen)
- dc->SetPen(pen);
- if (brush)
- dc->SetBrush(brush);
- dc->DrawEllipse((xpos - width/2), (ypos - height/2), width, height);
- }
- }
-
- void EllipseObject::SetSize(float x, float y)
- {
- width = x;
- height = y;
- }
-
- void EllipseObject::Copy(EllipseObject& copy)
- {
- CanvasObject::Copy(copy);
-
- copy.width = width;
- copy.height = height;
- }
-
- int EllipseObject::GetNumberOfAttachments(void)
- {
- return 4;
- }
-
- // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
- // 3 = left.
- void EllipseObject::GetAttachmentPosition(int attachment, float *x, float *y,
- int nth, int no_arcs)
- {
- if (attachment_mode)
- {
- float top = (float)(ypos + height/2.0);
- float bottom = (float)(ypos - height/2.0);
- float left = (float)(xpos - width/2.0);
- float right = (float)(xpos + width/2.0);
- switch (attachment)
- {
- case 0:
- {
- *x = left + (nth + 1)*width/(no_arcs + 1);
- *y = top;
- break;
- }
- case 1:
- {
- *x = right;
- *y = bottom + (nth + 1)*height/(no_arcs + 1);
- break;
- }
- case 2:
- {
- *x = left + (nth + 1)*width/(no_arcs + 1);
- *y = bottom;
- break;
- }
- case 3:
- {
- *x = left;
- *y = bottom + (nth + 1)*height/(no_arcs + 1);
- break;
- }
- default:
- {
- *x = xpos; *y = ypos;
- break;
- }
- }
- }
- else
- { *x = xpos; *y = ypos; }
- }
-
-
- // Circle object
- CircleObject::CircleObject(float diameter):EllipseObject(diameter, diameter)
- {
- }
-
- Bool CircleObject::GetPerimeterPoint(float x1, float y1,
- float x2, float y2,
- float *x3, float *y3)
- {
- find_end_for_circle(width/2,
- xpos, ypos, // Centre of circle
- x2, y2, // Other end of line
- x3, y3);
-
- return TRUE;
- }
-
- // Line object
-
- LineObject::LineObject(void)
- {
- xpos1 = 0.0; ypos1 = 0.0; xpos2 = 0.0; ypos2 = 0.0;
- SetArrowSize(10, 5);
- SetStartArrow(ARROW_NONE);
- SetEndArrow(ARROW_NONE);
- SetMiddleArrow(ARROW_NONE);
- linked_up = FALSE;
- attachment_to = 0;
- attachment_from = 0;
- actual_text_width = 0.0;
- actual_text_height = 0.0;
-
- line_control_points = NULL;
- }
-
- LineObject::LineObject(wxList *list)
- {
- line_control_points = list;
- }
-
- LineObject::~LineObject(void)
- {
- if (line_control_points)
- {
- wxNode *node = line_control_points->First();
- while (node)
- {
- wxPoint *cp = (wxPoint *)node->Data();
- delete cp;
- node = node->Next();
- }
- delete line_control_points;
- }
- }
-
- void LineObject::MakeLineControlPoints(int n)
- {
- if (line_control_points)
- {
- wxNode *node = line_control_points->First();
- while (node)
- {
- wxPoint *cp = (wxPoint *)node->Data();
- delete cp;
- node = node->Next();
- }
- delete line_control_points;
- }
- line_control_points = new wxList;
-
- int i = 0;
- for (i = 0; i < n; i++)
- {
- wxPoint *point = new wxPoint(-999, -999);
- line_control_points->Append(point);
- }
- }
-
- void LineObject::InsertLineControlPoint(void)
- {
- Erase();
-
- wxNode *last = line_control_points->Last();
- wxNode *second_last = last->Previous();
- wxPoint *last_point = (wxPoint *)last->Data();
- wxPoint *second_last_point = (wxPoint *)second_last->Data();
-
- // Choose a point half way between the last and penultimate points
- float line_x = ((last_point->x + second_last_point->x)/2);
- float line_y = ((last_point->y + second_last_point->y)/2);
-
- wxPoint *point = new wxPoint(line_x, line_y);
- line_control_points->Insert(last, point);
- }
-
- Bool LineObject::DeleteLineControlPoint(void)
- {
- if (line_control_points->Number() < 3)
- return FALSE;
-
- wxNode *last = line_control_points->Last();
- wxNode *second_last = last->Previous();
-
- wxPoint *second_last_point = (wxPoint *)second_last->Data();
- delete second_last_point;
- delete second_last;
-
- return TRUE;
- }
-
- void LineObject::Initialise(void)
- {
- if (line_control_points)
- {
- // Just move the first and last control points
- wxNode *first = line_control_points->First();
- wxPoint *first_point = (wxPoint *)first->Data();
-
- wxNode *last = line_control_points->Last();
- wxPoint *last_point = (wxPoint *)last->Data();
- first_point->x = xpos1;
- first_point->y = ypos1;
- last_point->x = xpos2;
- last_point->y = ypos2;
-
- // 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->Next();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- if (point->x == -999)
- {
- float x1, y1, x2, y2;
- if (from->xpos < to->xpos)
- { x1 = from->xpos; x2 = to->xpos; }
- else
- { x2 = from->xpos; x1 = to->xpos; }
-
- if (from->ypos < to->ypos)
- { y1 = from->ypos; y2 = to->ypos; }
- else
- { y2 = from->ypos; y1 = to->ypos; }
-
- point->x = ((x2 - x1)/2 + x1);
- point->y = ((y2 - y1)/2 + y1);
- }
- node = node->Next();
- }
- }
- }
-
-
- void LineObject::FormatText(char *s)
- {
- if (!dc)
- return;
-
- ClearText();
-
- float w = 100.0;
- float h = 50.0;
-
- // What should the label bounding box be really?? User definable??
- wxList *string_list = ::FormatText(dc, s, w, h);
- wxNode *node = string_list->First();
- while (node)
- {
- char *s = (char *)node->Data();
- CanvasObjectTextLine *line = new CanvasObjectTextLine(0.0, 0.0, s);
- text.Append((wxObject *)line);
- delete node;
- node = string_list->First();
- }
- delete string_list;
- CentreText(dc, &text, xpos, ypos, w, h);
-
- if (font) dc->SetFont(font);
-
- GetCentredTextExtent(dc, &text, xpos, ypos, w, h,
- &actual_text_width, &actual_text_height);
- formatted = TRUE;
- }
-
- /*
- * Find whether line is supposed to be vertical or horizontal and
- * make it so.
- *
- */
- void GraphicsStraightenLine(wxPoint *point1, wxPoint *point2)
- {
- float dx = point2->x - point1->x;
- float 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 LineObject::Straighten(void)
- {
- if (!line_control_points || line_control_points->Number() < 3)
- return;
-
- Erase();
-
- wxNode *first_point_node = line_control_points->First();
- wxNode *last_point_node = line_control_points->Last();
- wxNode *second_last_point_node = last_point_node->Previous();
-
- wxPoint *last_point = (wxPoint *)last_point_node->Data();
- wxPoint *second_last_point = (wxPoint *)second_last_point_node->Data();
-
- GraphicsStraightenLine(last_point, second_last_point);
-
- wxNode *node = first_point_node;
- while (node && (node != second_last_point_node))
- {
- wxPoint *point = (wxPoint *)node->Data();
- wxPoint *next_point = (wxPoint *)(node->Next()->Data());
-
- GraphicsStraightenLine(point, next_point);
- node = node->Next();
- }
-
- Draw();
- }
-
-
- void LineObject::Unlink(void)
- {
- if (to)
- to->lines.DeleteObject(this);
- if (from)
- from->lines.DeleteObject(this);
- to = NULL;
- from = NULL;
- }
-
- void LineObject::SetEnds(float x1, float y1, float x2, float y2)
- {
- // Find centre point
- float min_x;
- float min_y;
- if (x1 < x2)
- min_x = x1;
- else min_x = x2;
-
- if (y1 < y2)
- min_y = y1;
- else min_y = y2;
-
- xpos = (float)(fabs((x2 - x1)/2.0) + min_x);
- ypos = (float)(fabs((y2 - y1)/2.0) + min_y);
-
- // Now find offsets from centre
- xpos1 = x1 - xpos; ypos1 = y1 - ypos;
- xpos2 = x2 - xpos; ypos2 = y2 - ypos;
- }
-
- // Get absolute positions of ends
- void LineObject::GetEnds(float *x1, float *y1, float *x2, float *y2)
- {
- *x1 = xpos1 + xpos; *y1 = ypos1 + ypos;
- *x2 = xpos2 + xpos; *y2 = ypos2 + ypos;
- }
-
- void LineObject::SetAttachments(int from_attach, int to_attach)
- {
- attachment_from = from_attach;
- attachment_to = to_attach;
- }
-
- Bool LineObject::HitTest(float x, float y, int *attachment, float *distance)
- {
- if (!line_control_points)
- return FALSE;
-
- wxNode *node = line_control_points->First();
-
- while (node && node->Next())
- {
- wxPoint *point1 = (wxPoint *)node->Data();
- wxPoint *point2 = (wxPoint *)node->Next()->Data();
-
- // Allow for inaccurate mousing or vert/horiz lines
- int extra = 4;
- float left = min(point1->x, point2->x) - extra;
- float right = max(point1->x, point2->x) + extra;
-
- float bottom = min(point1->y, point2->y) - extra;
- float top = max(point1->y, point2->y) + extra;
-
- if (x > left && x < right && y > bottom && y < top)
- {
- // Work out distance from centre of line
- float centre_x = left + (right - left)/2.0;
- float centre_y = bottom + (top - bottom)/2.0;
-
- *attachment = 0;
- *distance = sqrt((centre_x - x)*(centre_x - x) + (centre_y - y)*(centre_y - y));
- return TRUE;
- }
-
- node = node->Next();
- }
- return FALSE;
- }
-
-
- void LineObject::DrawArrows(void)
- {
- if (dc)
- {
-
- switch (end_style)
- {
- case ARROW_ONE:
- {
- float x1, y1, x2, y2;
- wxNode *last_line_node = line_control_points->Last();
- wxPoint *last_line_point = (wxPoint *)last_line_node->Data();
- wxNode *second_last_line_node = last_line_node->Previous();
- wxPoint *second_last_line_point = (wxPoint *)second_last_line_node->Data();
-
- x2 = (float)last_line_point->x;
- y2 = (float)last_line_point->y;
- x1 = (float)second_last_line_point->x;
- y1 = (float)second_last_line_point->y;
-
- float tip_x, tip_y, side1_x, side1_y, side2_x, side2_y;
- get_arrow_points(x1, y1, x2, y2, arrow_length, arrow_width, &tip_x, &tip_y,
- &side1_x, &side1_y, &side2_x, &side2_y);
-
- wxPoint points[4];
- points[0].x = tip_x; points[0].y = tip_y;
- points[1].x = side1_x; points[1].y = side1_y;
- points[2].x = side2_x; points[2].y = side2_y;
- points[3].x = tip_x; points[3].y = tip_y;
-
- dc->DrawPolygon(4, points);
- break;
- }
- case ARROW_BOTH:
- {
- float x1, y1, x2, y2;
- wxNode *last_line_node = line_control_points->Last();
- wxPoint *last_line_point = (wxPoint *)last_line_node->Data();
- wxNode *second_last_line_node = last_line_node->Previous();
- wxPoint *second_last_line_point = (wxPoint *)second_last_line_node->Data();
-
- x2 = (float)last_line_point->x;
- y2 = (float)last_line_point->y;
- x1 = (float)second_last_line_point->x;
- y1 = (float)second_last_line_point->y;
-
- float tip_x, tip_y, side1_x, side1_y, side2_x, side2_y;
- get_arrow_points(x1, y1, x2, y2, arrow_length, arrow_width, &tip_x, &tip_y,
- &side1_x, &side1_y, &side2_x, &side2_y);
-
- wxPoint points[4];
- points[0].x = tip_x; points[0].y = tip_y;
- points[1].x = side1_x; points[1].y = side1_y;
- points[2].x = side2_x; points[2].y = side2_y;
- points[3].x = tip_x; points[3].y = tip_y;
-
- dc->DrawPolygon(4, points);
-
- // Other end
- last_line_node = line_control_points->First();
- last_line_point = (wxPoint *)last_line_node->Data();
- second_last_line_node = last_line_node->Next();
- second_last_line_point = (wxPoint *)second_last_line_node->Data();
-
- x2 = (float)last_line_point->x;
- y2 = (float)last_line_point->y;
- x1 = (float)second_last_line_point->x;
- y1 = (float)second_last_line_point->y;
-
- get_arrow_points(x1, y1, x2, y2, arrow_length, arrow_width, &tip_x, &tip_y,
- &side1_x, &side1_y, &side2_x, &side2_y);
-
- points[0].x = tip_x; points[0].y = tip_y;
- points[1].x = side1_x; points[1].y = side1_y;
- points[2].x = side2_x; points[2].y = side2_y;
- points[3].x = tip_x; points[3].y = tip_y;
-
- dc->DrawPolygon(4, points);
- break;
- }
- case ARROW_NONE:
- default: break;
- }
- }
- }
-
-
- void LineObject::OnErase(void)
- {
- if (dc)
- {
- wxPen *old_pen = pen;
- wxBrush *old_brush = brush;
- SetPen(white_background_pen);
- SetBrush(white_background_brush);
-
- float bound_x, bound_y;
- GetBoundingBox(&bound_x, &bound_y);
- if (font) dc->SetFont(font);
-
- // Undraw text
- dc->SetPen(white_background_pen);
- dc->SetBrush(white_background_brush);
-
- // Want to take the middle section for the label
- int n = line_control_points->Number();
- int half_way = (int)(n/2);
-
- // Find middle of this line
- wxNode *node = line_control_points->Nth(half_way - 1);
- wxPoint *point = (wxPoint *)node->Data();
- wxNode *next_node = node->Next();
- wxPoint *next_point = (wxPoint *)next_node->Data();
-
- float dx = (next_point->x - point->x);
- float dy = (next_point->y - point->y);
- float x = point->x + dx/2.0;
- float y = point->y + dy/2.0;
-
- dc->DrawRectangle(
- (float)(x - actual_text_width/2.0), (float)(y - actual_text_height/2.0),
- (float)actual_text_width, (float)actual_text_height);
-
- // Undraw line
- SetPen(white_background_pen);
- SetBrush(white_background_brush);
-
- OnDraw();
- OnEraseControlPoints();
-
- if (old_pen) SetPen(old_pen);
- if (old_brush) SetBrush(old_brush);
- }
- }
-
- void LineObject::GetBoundingBox(float *w, float *h)
- {
- float x1 = 10000;
- float y1 = 10000;
- float x2 = -10000;
- float y2 = -10000;
-
- wxNode *node = line_control_points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
-
- 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->Next();
- }
- *w = (float)(x2 - x1);
- *h = (float)(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 LineObject::FindNth(CanvasObject *image, int *nth, int *no_arcs)
- {
- int n = -1;
- int num = 0;
- wxNode *node = image->lines.First();
- int this_attachment;
- if (image == to)
- this_attachment = attachment_to;
- else
- this_attachment = attachment_from;
-
- // Find number of lines going into/out of this particular attachment point
- while (node)
- {
- LineObject *line = (LineObject *)node->Data();
-
- // This is the nth line attached to 'image'
- if (line == this)
- n = num;
-
- if (line->to == image)
- {
- // Increment num count if this is the same side (attachment number)
- if (line->attachment_to == this_attachment)
- num ++;
- }
- if (line->from == image)
- {
- // Increment num count if this is the same side (attachment number)
- if (line->attachment_from == this_attachment)
- num ++;
- }
- node = node->Next();
- }
- *nth = n;
- *no_arcs = num;
- }
-
- void LineObject::OnDrawOutline(void)
- {
- wxPen *old_pen = pen;
- wxBrush *old_brush = brush;
-
- SetPen(black_dashed_pen);
- SetBrush(transparent_brush);
-
- OnDraw();
-
- if (old_pen) SetPen(old_pen);
- if (old_brush) SetBrush(old_brush);
- }
-
- void LineObject::OnMove(float x, float y, float old_x, float old_y)
- {
- float x_offset = x - old_x;
- float y_offset = y - old_y;
-
- if (line_control_points && !(x_offset == 0.0 && y_offset == 0.0))
- {
- wxNode *node = line_control_points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- point->x += x_offset;
- point->y += y_offset;
- node = node->Next();
- }
-
- }
- find_polyline_centroid(line_control_points, &xpos, &ypos);
- }
-
- void LineObject::OnMoveLink(void)
- {
- if (dc)
- {
- if (line_control_points->Number() > 2)
- Initialise();
-
- // Do each end - nothing in the middle. User has to move other points
- // manually if necessary.
- float end_x, end_y;
- float other_end_x, other_end_y;
-
- wxNode *first = line_control_points->First();
- wxPoint *first_point = (wxPoint *)first->Data();
- wxNode *last = line_control_points->Last();
- wxPoint *last_point = (wxPoint *)last->Data();
-
- wxNode *second = first->Next();
- wxPoint *second_point = (wxPoint *)second->Data();
-
- wxNode *second_last = last->Previous();
- wxPoint *second_last_point = (wxPoint *)second_last->Data();
-
- // Should use to->xpos rather than other current end!
- if (line_control_points->Number() > 2)
- {
- if (from->attachment_mode)
- {
- int nth, no_arcs;
- FindNth(from, &nth, &no_arcs);
- from->GetAttachmentPosition(attachment_from, &end_x, &end_y, nth, no_arcs);
- }
- else
- (void)from->GetPerimeterPoint(from->xpos, from->ypos,
- (float)second_point->x, (float)second_point->y,
- &end_x, &end_y);
-
- if (to->attachment_mode)
- {
- int nth, no_arcs;
- FindNth(to, &nth, &no_arcs);
- to->GetAttachmentPosition(attachment_to, &other_end_x, &other_end_y, nth, no_arcs);
- }
- else
- (void)to->GetPerimeterPoint(to->xpos, to->ypos,
- (float)second_last_point->x, (float)second_last_point->y,
- &other_end_x, &other_end_y);
- }
- else
- {
- if (from->attachment_mode)
- {
- int nth, no_arcs;
- FindNth(from, &nth, &no_arcs);
- from->GetAttachmentPosition(attachment_from, &end_x, &end_y, nth, no_arcs);
- }
- else
- (void)from->GetPerimeterPoint(from->xpos, from->ypos,
- to->xpos, to->ypos,
- &end_x, &end_y);
-
- if (to->attachment_mode)
- {
- int nth, no_arcs;
- FindNth(to, &nth, &no_arcs);
- to->GetAttachmentPosition(attachment_to, &other_end_x, &other_end_y, nth, no_arcs);
- }
- else
- (void)to->GetPerimeterPoint(to->xpos, to->ypos,
- from->xpos, from->ypos,
- &other_end_x, &other_end_y);
- }
-
- first_point->x = end_x; first_point->y = end_y;
- last_point->x = other_end_x; last_point->y = other_end_y;
-
- SetEnds(end_x, end_y, other_end_x, other_end_y);
- Move(xpos, ypos);
-
- }
- }
-
- void LineObject::OnDraw(void)
- {
- if (dc && line_control_points)
- {
- if (pen)
- dc->SetPen(pen);
- if (brush)
- dc->SetBrush(brush);
-
- dc->DrawLines(line_control_points);
- DrawArrows();
- }
- }
-
- void LineObject::OnDragLeft(Bool draw, float x, float y, int keys, int attachment)
- {
- }
-
- void LineObject::OnBeginDragLeft(float x, float y, int keys, int attachment)
- {
- }
-
- void LineObject::OnEndDragLeft(float x, float y, int keys, int attachment)
- {
- }
-
- void LineObject::SetArrowSize(float length, float width)
- {
- arrow_length = length;
- arrow_width = width;
- }
-
- void LineObject::SetStartArrow(int style)
- {
- start_style = style;
- }
-
- void LineObject::SetMiddleArrow(int style)
- {
- middle_style = style;
- }
-
- void LineObject::SetEndArrow(int style)
- {
- end_style = style;
- }
-
- void LineObject::OnDrawContents(void)
- {
- if (disable_label)
- return;
-
- // Want to take the middle section for the label
- int n = line_control_points->Number();
- int half_way = (int)(n/2);
-
- // Find middle of this line
- wxNode *node = line_control_points->Nth(half_way - 1);
- wxPoint *point = (wxPoint *)node->Data();
- wxNode *next_node = node->Next();
- wxPoint *next_point = (wxPoint *)next_node->Data();
-
- float dx = (next_point->x - point->x);
- float dy = (next_point->y - point->y);
- float x = point->x + dx/2.0;
- float y = point->y + dy/2.0;
-
- float bound_x, bound_y;
- GetBoundingBox(&bound_x, &bound_y);
- if (dc)
- {
- // First, clear a rectangle for the text IF there is any
- if (text.Number() > 0)
- {
- dc->SetPen(white_background_pen);
- dc->SetBrush(white_background_brush);
-
- // Now draw the text
- if (font) dc->SetFont(font);
-
- if (!formatted || (actual_text_width == 0.0 && actual_text_height == 0.0))
- {
- GetCentredTextExtent(dc, &text, x, y, bound_x, bound_y,
- &actual_text_width, &actual_text_height);
- }
-
- dc->DrawRectangle((float)(x - actual_text_width/2.0), (float)(y - actual_text_height/2.0),
- (float)actual_text_width, (float)actual_text_height);
-
- if (pen) dc->SetPen(pen);
- if (text_colour) dc->SetTextForeground(text_colour);
-
- #ifdef wx_msw
- dc->SetTextBackground(white_background_brush->colour);
- #endif
-
- if (!formatted)
- {
- CentreTextNoClipping(dc, &text, x, y, actual_text_width, actual_text_height);
- formatted = TRUE;
- }
- DrawFormattedText(dc, &text, x, y, actual_text_width, actual_text_height);
- }
- }
- }
-
- CanvasObject *LineObject::GetTo(void)
- {
- return to;
- }
-
- CanvasObject *LineObject::GetFrom(void)
- {
- return from;
- }
-
- void LineObject::SetTo(CanvasObject *object)
- {
- to = object;
- }
-
- void LineObject::SetFrom(CanvasObject *object)
- {
- from = object;
- }
-
- void LineObject::MakeControlPoints(void)
- {
- if (canvas && dc && line_control_points)
- {
- wxNode *first = line_control_points->First();
- wxNode *last = line_control_points->Last();
- wxPoint *first_point = (wxPoint *)first->Data();
- wxPoint *last_point = (wxPoint *)last->Data();
-
- LineControlPoint *control = new LineControlPoint(canvas, this, CONTROL_POINT_SIZE,
- first_point->x, first_point->y,
- CONTROL_POINT_ENDPOINT_FROM);
- control->point = first_point;
- canvas->AddObject(control);
- control_points.Append(control);
-
-
- wxNode *node = first->Next();
- while (node != last)
- {
- wxPoint *point = (wxPoint *)node->Data();
-
- control = new LineControlPoint(canvas, this, CONTROL_POINT_SIZE,
- point->x, point->y,
- CONTROL_POINT_LINE);
- control->point = point;
-
- canvas->AddObject(control);
- control_points.Append(control);
-
- node = node->Next();
- }
- control = new LineControlPoint(canvas, this, CONTROL_POINT_SIZE,
- last_point->x, last_point->y,
- CONTROL_POINT_ENDPOINT_TO);
- control->point = last_point;
- canvas->AddObject(control);
- control_points.Append(control);
-
- }
-
- }
-
- void LineObject::ResetControlPoints(void)
- {
- if (canvas && line_control_points && control_points.Number() > 0)
- {
- wxNode *node = control_points.First();
- wxNode *control_node = line_control_points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)control_node->Data();
- LineControlPoint *control = (LineControlPoint *)node->Data();
- control->xpos = point->x;
- control->ypos = point->y;
-
- node = node->Next();
- control_node = control_node->Next();
- }
- }
- }
-
- void LineObject::Copy(LineObject& copy)
- {
- CanvasObject::Copy(copy);
-
- copy.xpos1 = xpos1;
- copy.xpos2 = xpos2;
- copy.ypos1 = ypos1;
- copy.ypos2 = ypos2;
-
- if (!copy.line_control_points)
- copy.line_control_points = new wxList;
-
- wxNode *node = line_control_points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- wxPoint *new_point = new wxPoint(point->x, point->y);
- copy.line_control_points->Append(new_point);
- node = node->Next();
- }
-
- copy.start_style = start_style;
- copy.end_style = end_style;
- copy.middle_style = middle_style;
-
- copy.arrow_length = arrow_length;
- copy.arrow_width = arrow_width;
- }
-
- // Spline object
-
- SplineObject::SplineObject(void)
- {
- line_control_points = NULL;
- }
-
- SplineObject::SplineObject(wxList *list)
- {
- line_control_points = list;
- }
-
- SplineObject::~SplineObject(void)
- {
- }
-
- void SplineObject::OnDraw(void)
- {
- if (dc && line_control_points)
- {
- if (pen)
- dc->SetPen(pen);
- if (brush)
- dc->SetBrush(brush);
-
- dc->DrawSpline(line_control_points);
- DrawArrows();
- }
- }
-
- Bool SplineObject::HitTest(float x, float y, int *attachment, float *distance)
- {
- return LineObject::HitTest(x, y, attachment, distance);
- }
-
- void SplineObject::Copy(SplineObject& copy)
- {
- LineObject::Copy(copy);
- }
-
- // Control points
- ControlPoint::ControlPoint(ObjectCanvas *the_canvas, CanvasObject *object, float size, float the_xoffset, float the_yoffset, int the_type):RectangleObject(size, size)
- {
- canvas = the_canvas;
- canvas_object = object;
- xoffset = the_xoffset;
- yoffset = the_yoffset;
- type = the_type;
- SetPen(black_foreground_pen);
- SetBrush(black_brush);
- old_cursor = NULL;
- visible = TRUE;
- }
-
- ControlPoint::~ControlPoint(void)
- {
- }
-
- // Don't even attempt to draw any text - waste of time!
- void ControlPoint::OnDrawContents(void)
- {
- }
-
- void ControlPoint::OnDraw(void)
- {
- xpos = canvas_object->GetX() + xoffset;
- ypos = canvas_object->GetY() + yoffset;
- RectangleObject::OnDraw();
- }
-
- void ControlPoint::OnErase(void)
- {
- RectangleObject::OnErase();
- }
-
- // Implement resizing of canvas object
- void ControlPoint::OnDragLeft(Bool draw, float x, float y, int keys, int attachment)
- {
- float bound_x;
- float bound_y;
- canvas_object->GetBoundingBox(&bound_x, &bound_y);
- float new_width = (float)(2.0*fabs(x - canvas_object->xpos));
- float new_height = (float)(2.0*fabs(y - canvas_object->ypos));
-
- // Constrain sizing according to what control point you're dragging
- if (type == CONTROL_POINT_HORIZONTAL)
- new_height = bound_y;
- if (type == CONTROL_POINT_VERTICAL)
- new_width = bound_x;
- if (type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
- {
- new_height = bound_y*(new_width/bound_x);
- }
-
- canvas_object->SetSize(new_width, new_height);
- canvas_object->OnDrawOutline();
- }
-
- void ControlPoint::OnBeginDragLeft(float x, float y, int keys, int attachment)
- {
- canvas_object->Erase();
-
- dc->SetLogicalFunction(wxXOR);
-
- float bound_x;
- float bound_y;
- canvas_object->GetBoundingBox(&bound_x, &bound_y);
- float new_width = (float)(2.0*fabs(x - canvas_object->xpos));
- float new_height = (float)(2.0*fabs(y - canvas_object->ypos));
-
- // Constrain sizing according to what control point you're dragging
- if (type == CONTROL_POINT_HORIZONTAL)
- new_height = bound_y;
- if (type == CONTROL_POINT_VERTICAL)
- new_width = bound_x;
- if (type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
- {
- new_height = bound_y*(new_width/bound_x);
- }
-
- canvas_object->SetSize(new_width, new_height);
- canvas_object->OnDrawOutline();
- }
-
- void ControlPoint::OnEndDragLeft(float x, float y, int keys, int attachment)
- {
- dc->SetLogicalFunction(wxCOPY);
- canvas_object->ResetControlPoints();
- canvas_object->Move(canvas_object->GetX(), canvas_object->GetY());
- if (!canvas->quick_edit_mode) canvas->Redraw();
- }
-
- int ControlPoint::GetNumberOfAttachments(void)
- {
- return 1;
- }
-
- void ControlPoint::GetAttachmentPosition(int attachment, float *x, float *y,
- int nth, int no_arcs)
- {
- *x = xpos; *y = ypos;
- }
-
-
- /*
- * Line control point
- *
- */
-
- LineControlPoint::LineControlPoint(ObjectCanvas *the_canvas, CanvasObject *object, float size, float x, float y, int the_type):
- ControlPoint(the_canvas, object, size, x, y, the_type)
- {
- xpos = x;
- ypos = y;
- type = the_type;
- }
-
- LineControlPoint::~LineControlPoint(void)
- {
- }
-
- void LineControlPoint::OnDraw(void)
- {
- RectangleObject::OnDraw();
- }
-
- // Implement movement of Line point
- void LineControlPoint::OnDragLeft(Bool draw, float x, float y, int keys, int attachment)
- {
- if (type == CONTROL_POINT_LINE)
- {
- canvas->Snap(&x, &y);
-
- xpos = x; ypos = y;
- point->x = x; point->y = y;
-
- LineObject *line_object = (LineObject *)canvas_object;
- wxPen *old_pen = line_object->pen;
- wxBrush *old_brush = line_object->brush;
-
- line_object->SetPen(black_dashed_pen);
- // line_object->SetBrush(transparent_brush);
-
- line_object->OnMoveLink();
-
- if (old_pen) line_object->SetPen(old_pen);
- if (old_brush) line_object->SetBrush(old_brush);
- }
-
- if (type == CONTROL_POINT_ENDPOINT_FROM || type == CONTROL_POINT_ENDPOINT_TO)
- {
- xpos = x; ypos = y;
- }
-
- }
-
- void LineControlPoint::OnBeginDragLeft(float x, float y, int keys, int attachment)
- {
- if (type == CONTROL_POINT_LINE)
- {
- canvas->Snap(&x, &y);
-
- canvas_object->Erase();
- canvas_object->disable_label = TRUE;
- dc->SetLogicalFunction(wxXOR);
-
- xpos = x; ypos = y;
- point->x = x; point->y = y;
-
- LineObject *line_object = (LineObject *)canvas_object;
- wxPen *old_pen = line_object->pen;
- wxBrush *old_brush = line_object->brush;
-
- line_object->SetPen(black_dashed_pen);
- // line_object->SetBrush(transparent_brush);
-
- line_object->OnMoveLink();
-
- if (old_pen) line_object->SetPen(old_pen);
- if (old_brush) line_object->SetBrush(old_brush);
- }
-
- if (type == CONTROL_POINT_ENDPOINT_FROM || type == CONTROL_POINT_ENDPOINT_TO)
- {
- old_cursor = canvas->SetCursor(GraphicsBullseyeCursor);
- }
- }
-
- void LineControlPoint::OnEndDragLeft(float x, float y, int keys, int attachment)
- {
- canvas_object->disable_label = FALSE;
- if (type == CONTROL_POINT_LINE)
- {
- canvas->Snap(&x, &y);
-
- dc->SetLogicalFunction(wxCOPY);
- xpos = x; ypos = y;
- point->x = x; point->y = y;
-
- LineObject *line_object = (LineObject *)canvas_object;
- line_object->OnMoveLink();
-
- if (!canvas->quick_edit_mode) canvas->Redraw();
- }
- if (type == CONTROL_POINT_ENDPOINT_FROM)
- {
- if (old_cursor)
- canvas->SetCursor(old_cursor);
-
- xpos = x; ypos = y;
-
- LineObject *line_object = (LineObject *)canvas_object;
- line_object->from->MoveLineToNewAttachment(line_object, x, y);
-
- line_object->from->MoveLinks();
-
- if (!canvas->quick_edit_mode) canvas->Redraw();
- }
- if (type == CONTROL_POINT_ENDPOINT_TO)
- {
- if (old_cursor)
- canvas->SetCursor(old_cursor);
-
- xpos = x; ypos = y;
-
- LineObject *line_object = (LineObject *)canvas_object;
- line_object->to->MoveLineToNewAttachment(line_object, x, y);
-
- line_object->to->MoveLinks();
-
- if (!canvas->quick_edit_mode) canvas->Redraw();
- }
- }
-
- // Implement movement of endpoint to a new attachment
- void LineControlPoint::OnDragRight(Bool draw, float x, float y, int keys, int attachment)
- {
- if (type == CONTROL_POINT_ENDPOINT_FROM || type == CONTROL_POINT_ENDPOINT_TO)
- {
- xpos = x; ypos = y;
- }
-
- }
-
- void LineControlPoint::OnBeginDragRight(float x, float y, int keys, int attachment)
- {
- if (type == CONTROL_POINT_ENDPOINT_FROM || type == CONTROL_POINT_ENDPOINT_TO)
- {
- old_cursor = canvas->SetCursor(GraphicsBullseyeCursor);
- }
- }
-
- void LineControlPoint::OnEndDragRight(float x, float y, int keys, int attachment)
- {
- if (type == CONTROL_POINT_ENDPOINT_FROM)
- {
- if (old_cursor)
- canvas->SetCursor(old_cursor);
-
- xpos = x; ypos = y;
-
- LineObject *line_object = (LineObject *)canvas_object;
- line_object->from->EraseLinks();
-
- int new_attachment;
- float distance;
- if (line_object->from->HitTest(x, y, &new_attachment, &distance))
- line_object->attachment_from = new_attachment;
-
- line_object->from->MoveLinks();
-
- if (!canvas->quick_edit_mode) canvas->Redraw();
- }
- if (type == CONTROL_POINT_ENDPOINT_TO)
- {
- if (old_cursor)
- canvas->SetCursor(old_cursor);
-
- xpos = x; ypos = y;
-
- LineObject *line_object = (LineObject *)canvas_object;
- line_object->to->EraseLinks();
-
- int new_attachment;
- float distance;
- if (line_object->to->HitTest(x, y, &new_attachment, &distance))
- line_object->attachment_to = new_attachment;
-
- line_object->to->MoveLinks();
-
- if (!canvas->quick_edit_mode) canvas->Redraw();
- }
- }
-
-
-
-
- // Object canvas
- ObjectCanvas::ObjectCanvas(wxFrame *frame, int x, int y, int w, int h, int style):
- wxCanvas(frame, x, y, w, h, style)
- {
- quick_edit_mode = FALSE;
- snap_to_grid = TRUE;
- grid_spacing = 5.0;
- object_list = new wxList;
- DragState = NoDragging;
- DraggedObject = NULL;
- old_drag_x = 0;
- old_drag_y = 0;
- }
-
- ObjectCanvas::~ObjectCanvas(void)
- {
- if (object_list)
- delete object_list;
- }
-
- void ObjectCanvas::SetSnapToGrid(Bool snap)
- {
- snap_to_grid = snap;
- }
-
- void ObjectCanvas::SetGridSpacing(float spacing)
- {
- grid_spacing = spacing;
- }
-
- void ObjectCanvas::Snap(float *x, float *y)
- {
- if (snap_to_grid)
- {
- *x = grid_spacing * ((int)(*x/grid_spacing + 0.5));
- *y = grid_spacing * ((int)(*y/grid_spacing + 0.5));
- }
- }
-
-
- void ObjectCanvas::OnPaint(void)
- {
- GetDC()->Clear();
-
- Redraw();
- }
-
- void ObjectCanvas::Redraw(void)
- {
- if (object_list)
- {
- wxCursor *old_cursor = SetCursor(wxHOURGLASS_CURSOR);
- wxNode *current = object_list->First();
-
- while (current)
- {
- CanvasObject *object = (CanvasObject *)current->Data();
- object->Draw();
-
- current = current->Next();
- }
-
- SetCursor(old_cursor);
- }
- }
-
- void ObjectCanvas::Clear(void)
- {
- wxCanvas::Clear();
- }
-
- ObjectCanvas *CanvasObject::GetCanvas(void)
- {
- return canvas;
- }
-
- void CanvasObject::SetCanvas(ObjectCanvas *the_canvas)
- {
- canvas = the_canvas;
- }
-
- void ObjectCanvas::AddObject(CanvasObject *object)
- {
- object_list->Append(object);
- object->SetCanvas(this);
- object->SetDC(context);
- }
-
- void ObjectCanvas::InsertObject(CanvasObject *object)
- {
- object_list->Insert(object);
- object->SetCanvas(this);
- }
-
- void ObjectCanvas::RemoveObject(CanvasObject *object)
- {
- object_list->DeleteObject(object);
- }
-
- // Should this delete the actual objects too? I think not.
- void ObjectCanvas::RemoveAllObjects(void)
- {
- object_list->Clear();
- }
-
- void ObjectCanvas::ShowAll(Bool show)
- {
- wxNode *current = object_list->First();
-
- while (current)
- {
- CanvasObject *object = (CanvasObject *)current->Data();
- object->Show(show);
-
- current = current->Next();
- }
- }
-
-
- void ObjectCanvas::OnEvent(wxEvent& event)
- {
- float x, y;
- event.Position(&x, &y);
- int keys = 0;
- if (event.ShiftDown())
- keys = keys | KEY_SHIFT;
- if (event.ControlDown())
- keys = keys | KEY_CTRL;
-
- // Dragging - note that the effect of dragging is left entirely up
- // to the object, so no movement is done unless explicitly done by
- // object.
- if (event.Dragging() && DraggedObject && DragState == StartDraggingLeft)
- {
- DragState = ContinueDraggingLeft;
- DraggedObject->OnBeginDragLeft((float)x, (float)y, keys, DraggedAttachment);
- old_drag_x = x; old_drag_y = y;
- }
- else if (event.Dragging() && DraggedObject && DragState == ContinueDraggingLeft)
- {
- // Continue dragging
- DraggedObject->OnDragLeft(FALSE, old_drag_x, old_drag_y, keys, DraggedAttachment);
- DraggedObject->OnDragLeft(TRUE, (float)x, (float)y, keys, DraggedAttachment);
- old_drag_x = x; old_drag_y = y;
- }
- else if (event.LeftUp() && DraggedObject && DragState == ContinueDraggingLeft)
- {
- DragState = NoDragging;
-
- DraggedObject->OnDragLeft(FALSE, old_drag_x, old_drag_y, keys, DraggedAttachment);
-
- DraggedObject->OnEndDragLeft((float)x, (float)y, keys, DraggedAttachment);
- DraggedObject = NULL;
- }
- else if (event.Dragging() && DraggedObject && DragState == StartDraggingRight)
- {
- DragState = ContinueDraggingRight;
- DraggedObject->OnBeginDragRight((float)x, (float)y, keys, DraggedAttachment);
- old_drag_x = x; old_drag_y = y;
- }
- else if (event.Dragging() && DraggedObject && DragState == ContinueDraggingRight)
- {
- // Continue dragging
- DraggedObject->OnDragRight(FALSE, old_drag_x, old_drag_y, keys, DraggedAttachment);
- DraggedObject->OnDragRight(TRUE, (float)x, (float)y, keys, DraggedAttachment);
- old_drag_x = x; old_drag_y = y;
- }
- else if (event.RightUp() && DraggedObject && DragState == ContinueDraggingRight)
- {
- DragState = NoDragging;
-
- DraggedObject->OnDragRight(FALSE, old_drag_x, old_drag_y, keys, DraggedAttachment);
-
- DraggedObject->OnEndDragRight((float)x, (float)y, keys, DraggedAttachment);
- DraggedObject = NULL;
- }
-
- // All following events sent to canvas, not object
- else if (event.Dragging() && !DraggedObject && DragState == StartDraggingLeft)
- {
- DragState = ContinueDraggingLeft;
- OnBeginDragLeft((float)x, (float)y, keys);
- old_drag_x = x; old_drag_y = y;
- }
- else if (event.Dragging() && !DraggedObject && DragState == ContinueDraggingLeft)
- {
- // Continue dragging
- OnDragLeft(FALSE, old_drag_x, old_drag_y, keys);
- OnDragLeft(TRUE, (float)x, (float)y, keys);
- old_drag_x = x; old_drag_y = y;
- }
- else if (event.LeftUp() && !DraggedObject && DragState == ContinueDraggingLeft)
- {
- DragState = NoDragging;
- OnDragLeft(FALSE, old_drag_x, old_drag_y, keys);
- OnEndDragLeft((float)x, (float)y, keys);
- DraggedObject = NULL;
- }
- else if (event.Dragging() && !DraggedObject && DragState == StartDraggingRight)
- {
- DragState = ContinueDraggingRight;
- OnBeginDragRight((float)x, (float)y, keys);
- old_drag_x = x; old_drag_y = y;
- }
- else if (event.Dragging() && !DraggedObject && DragState == ContinueDraggingRight)
- {
- // Continue dragging
- OnDragRight(FALSE, old_drag_x, old_drag_y, keys);
- OnDragRight(TRUE, (float)x, (float)y, keys);
- old_drag_x = x; old_drag_y = y;
- }
- else if (event.RightUp() && !DraggedObject && DragState == ContinueDraggingRight)
- {
- DragState = NoDragging;
-
- OnDragRight(FALSE, old_drag_x, old_drag_y, keys);
- OnEndDragRight((float)x, (float)y, keys);
- DraggedObject = NULL;
- }
-
- // Non-dragging events
- else if (event.IsButton())
- {
- // Find the nearest object
- int attachment = 0;
- CanvasObject *nearest_object = FindObject(x, y, &attachment);
-
- if (nearest_object) // Object event
- {
- if (event.LeftDown())
- {
- if (nearest_object->draggable)
- {
- DraggedObject = nearest_object;
- DraggedAttachment = attachment;
- DragState = StartDraggingLeft;
- }
- }
- else if (event.LeftUp())
- {
- // N.B. Only register a click if the same object was
- // identified for down *and* up.
- if (nearest_object == DraggedObject)
- nearest_object->OnLeftClick((float)x, (float)y, keys, attachment);
-
- DraggedObject = NULL;
- DragState = NoDragging;
- }
- else if (event.RightDown())
- {
- if (nearest_object->draggable)
- {
- DraggedObject = nearest_object;
- DraggedAttachment = attachment;
- DragState = StartDraggingRight;
- }
- }
- else if (event.RightUp())
- {
- if (nearest_object == DraggedObject)
- nearest_object->OnRightClick((float)x, (float)y, keys, attachment);
-
- DraggedObject = NULL;
- DragState = NoDragging;
- }
- }
- else // Canvas event (no nearest object)
- {
- if (event.LeftDown())
- {
- DraggedObject = NULL;
- DragState = StartDraggingLeft;
- }
- else if (event.LeftUp())
- {
- OnLeftClick((float)x, (float)y, keys);
-
- DraggedObject = NULL;
- DragState = NoDragging;
- }
- else if (event.RightDown())
- {
- DraggedObject = NULL;
- DragState = StartDraggingRight;
- }
- else if (event.RightUp())
- {
- OnRightClick((float)x, (float)y, keys);
-
- DraggedObject = NULL;
- DragState = NoDragging;
- }
- }
- }
- }
-
- CanvasObject *ObjectCanvas::FindObject(float x, float y, int *attachment)
- {
- float nearest = 100000.0;
- int nearest_attachment = 0;
- CanvasObject *nearest_object = NULL;
-
- // Go backward through the object list, since we want:
- // (a) to have the control points drawn LAST to overlay
- // the other objects
- // (b) to find the control points FIRST if they exist
-
- wxNode *current = object_list->Last();
- while (current)
- {
- CanvasObject *object = (CanvasObject *)current->Data();
-
- float dist;
- int temp_attachment;
-
- if (object->HitTest(x, y, &temp_attachment, &dist))
- {
- if (dist < nearest)
- {
- nearest = dist;
- nearest_object = object;
- nearest_attachment = temp_attachment;
- }
- }
-
- current = current->Previous();
- }
-
- *attachment = nearest_attachment;
- return nearest_object;
- }
-
- void ObjectCanvas::DrawOutline(float x1, float y1, float x2, float y2)
- {
- wxDC *dc = GetDC();
-
- dc->SetPen(black_dashed_pen);
- dc->SetBrush(transparent_brush);
-
- dc->DrawLine(x1, y1, x2, y1);
- dc->DrawLine(x2, y1, x2, y2);
- dc->DrawLine(x2, y2, x1, y2);
- dc->DrawLine(x1, y2, x1, y1);
- }
-
- /*
- * Higher-level events called by OnEvent
- *
- */
-
- void ObjectCanvas::OnLeftClick(float x, float y, int keys)
- {
- }
-
- void ObjectCanvas::OnRightClick(float x, float y, int keys)
- {
- }
-
- void ObjectCanvas::OnDragLeft(Bool draw, float x, float y, int keys)
- {
- }
-
- void ObjectCanvas::OnBeginDragLeft(float x, float y, int keys)
- {
- }
-
- void ObjectCanvas::OnEndDragLeft(float x, float y, int keys)
- {
- }
-
- void ObjectCanvas::OnDragRight(Bool draw, float x, float y, int keys)
- {
- }
-
- void ObjectCanvas::OnBeginDragRight(float x, float y, int keys)
- {
- }
-
- void ObjectCanvas::OnEndDragRight(float x, float y, int keys)
- {
- }
-
- // Centre a list of strings in the given box
- void CentreText(wxDC *context, wxList *text_list,
- float xpos, float ypos, float width, float height)
- {
- int n = text_list->Number();
-
- if (!text_list || (n == 0))
- return;
-
- // First, get maximum dimensions of box enclosing text
-
- float char_height = 0;
- float max_width = 0;
- float current_width = 0;
-
- // Store text extents for speed
- float *widths = new float[n];
-
- wxNode *current = text_list->First();
- int i = 0;
- while (current)
- {
- // char *string = (char *)current->Data();
- CanvasObjectTextLine *line = (CanvasObjectTextLine *)current->Data();
- context->GetTextExtent(line->line, ¤t_width, &char_height);
- widths[i] = current_width;
-
- if (current_width > max_width)
- max_width = current_width;
- current = current->Next();
- i ++;
- }
-
- float max_height = n*char_height;
-
- float yoffset;
-
- if (max_height < height)
- yoffset = (float)(ypos - (height/2.0) + (height - max_height)/2.0);
- else
- yoffset = (float)(ypos - (height/2.0));
-
- float xoffset = (float)(xpos - width/2.0);
-
- current = text_list->First();
- i = 0;
-
- while (current)
- {
- CanvasObjectTextLine *line = (CanvasObjectTextLine *)current->Data();
-
- float x;
- if (widths[i] < width)
- x = (float)((width - widths[i])/2.0 + xoffset);
- else
- x = xoffset;
- float y = (float)(i*char_height + yoffset);
-
- line->x = x - xpos; line->y = y - ypos;
- current = current->Next();
- i ++;
- }
-
- delete widths;
- }
-
- // Centre a list of strings in the given box
- void CentreTextNoClipping(wxDC *context, wxList *text_list,
- float xpos, float ypos, float width, float height)
- {
- int n = text_list->Number();
-
- if (!text_list || (n == 0))
- return;
-
- // First, get maximum dimensions of box enclosing text
-
- float char_height = 0;
- float max_width = 0;
- float current_width = 0;
-
- // Store text extents for speed
- float *widths = new float[n];
-
- wxNode *current = text_list->First();
- int i = 0;
- while (current)
- {
- CanvasObjectTextLine *line = (CanvasObjectTextLine *)current->Data();
- context->GetTextExtent(line->line, ¤t_width, &char_height);
- widths[i] = current_width;
-
- if (current_width > max_width)
- max_width = current_width;
- current = current->Next();
- i ++;
- }
-
- float max_height = n*char_height;
-
- float yoffset = (float)(ypos - (height/2.0) + (height - max_height)/2.0);
-
- float xoffset = (float)(xpos - width/2.0);
-
- current = text_list->First();
- i = 0;
-
- while (current)
- {
- CanvasObjectTextLine *line = (CanvasObjectTextLine *)current->Data();
-
- float x = (float)((width - widths[i])/2.0 + xoffset);
- float y = (float)(i*char_height + yoffset);
-
- line->x = x - xpos; line->y = y - ypos;
- current = current->Next();
- i ++;
- }
- delete widths;
- }
-
- void GetCentredTextExtent(wxDC *context, wxList *text_list,
- float xpos, float ypos, float width, float height,
- float *actual_width, float *actual_height)
- {
- int n = text_list->Number();
-
- if (!text_list || (n == 0))
- {
- *actual_width = 0;
- *actual_height = 0;
- return;
- }
-
- // First, get maximum dimensions of box enclosing text
-
- float char_height = 0;
- float max_width = 0;
- float current_width = 0;
-
- wxNode *current = text_list->First();
- int i = 0;
- while (current)
- {
- CanvasObjectTextLine *line = (CanvasObjectTextLine *)current->Data();
- context->GetTextExtent(line->line, ¤t_width, &char_height);
-
- if (current_width > max_width)
- max_width = current_width;
- current = current->Next();
- i ++;
- }
-
- *actual_height = n*char_height;
- *actual_width = max_width;
- }
-
- // Format a string to a list of strings that fit in the given box.
- // Interpret %n as a new line.
- wxList *FormatText(wxDC *context, char *text, float width, float height)
- {
- // First, parse the string into a list of words
- wxList word_list;
-
- // Make new lines into NULL strings at this point
- int i = 0; int j = 0; int len = strlen(text);
- char word[100]; word[0] = 0;
- Bool end_word = FALSE; Bool new_line = FALSE;
- while (i < len)
- {
- switch (text[i])
- {
- case '%':
- {
- i ++;
- if (i == len)
- { word[j] = '%'; j ++; }
- else
- {
- if (text[i] == 'n')
- { new_line = TRUE; end_word = TRUE; i++; }
- else
- { word[j] = '%'; j ++; word[j] = text[i]; j ++; i ++; }
- }
- break;
- }
- case ' ':
- {
- end_word = TRUE;
- i ++;
- break;
- }
- default:
- {
- word[j] = text[i];
- j ++; i ++;
- break;
- }
- }
- if (i == len) end_word = TRUE;
- if (end_word)
- {
- word[j] = 0;
- j = 0;
- word_list.Append((wxObject *)copystring(word));
- end_word = FALSE;
- }
- if (new_line)
- {
- word_list.Append((wxObject *)NULL);
- new_line = FALSE;
- }
- }
- // Now, make a list of strings which can fit in the box
- wxList *string_list = new wxList;
-
- char buffer[200];
- buffer[0] = 0;
- wxNode *node = word_list.First();
- float x, y;
-
- while (node)
- {
- char *keep_string = copystring(buffer);
-
- char *s = (char *)node->Data();
- if (!s)
- {
- // FORCE NEW LINE
- if (strlen(keep_string) > 0)
- string_list->Append((wxObject *)keep_string);
- else
- delete keep_string;
-
- buffer[0] = 0;
- }
- else
- {
- if (buffer[0] != 0)
- strcat(buffer, " ");
-
- strcat(buffer, s);
- context->GetTextExtent(buffer, &x, &y);
-
- if (x > width)
- {
- // Deal with first word being wider than box
- if (strlen(keep_string) > 0)
- string_list->Append((wxObject *)keep_string);
- else
- delete keep_string;
-
- buffer[0] = 0;
- strcat(buffer, s);
- delete s;
- }
- else
- delete keep_string;
- }
-
- node = node->Next();
- }
- if (buffer[0] != 0)
- string_list->Append((wxObject *)copystring(buffer));
-
- return string_list;
- }
-
- void DrawFormattedText(wxDC *context, wxList *text_list,
- float xpos, float ypos, float width, float height)
- {
- context->SetClippingRegion(
- (float)(xpos - width/2.0), (float)(ypos - height/2.0),
- (float)width, (float)height);
-
- wxNode *current = text_list->First();
- while (current)
- {
- CanvasObjectTextLine *line = (CanvasObjectTextLine *)current->Data();
-
- context->DrawText(line->line, xpos + line->x, ypos + line->y);
- current = current->Next();
- }
-
- context->DestroyClippingRegion();
- }
-
- /*
- * Find centroid given list of points comprising polyline
- *
- */
-
- void find_polyline_centroid(wxList *points, float *x, float *y)
- {
- float xcount = 0;
- float ycount = 0;
-
- wxNode *node = points->First();
- while (node)
- {
- wxPoint *point = (wxPoint *)node->Data();
- xcount += point->x;
- ycount += point->y;
- node = node->Next();
- }
-
- *x = (xcount/points->Number());
- *y = (ycount/points->Number());
- }
-
- /*
- * Check that (x1, y1) -> (x2, y2) hits (x3, y3) -> (x4, y4).
- * If so, ratio1 gives the proportion along the first line
- * that the intersection occurs (or something like that).
- * Used by functions below.
- *
- */
- void check_line_intersection(float x1, float y1, float x2, float y2,
- float x3, float y3, float x4, float y4,
- float *ratio1, float *ratio2)
- {
- float denominator_term = (y4 - y3)*(x2 - x1) - (y2 - y1)*(x4 - x3);
- float numerator_term = (x3 - x1)*(y4 - y3) + (x4 - x3)*(y1 - y3);
-
- float line_constant;
- float length_ratio = 1.0;
- float k_line = 1.0;
-
- // Check for parallel lines
- if ((denominator_term < 0.005) && (denominator_term > -0.005))
- line_constant = -1.0;
- else
- line_constant = numerator_term/denominator_term;
-
- // Check for intersection
- if ((line_constant < 1.0) && (line_constant > 0.0))
- {
- // Now must check that other line hits
- if (((y4 - y3) < 0.005) && ((y4 - y3) > -0.005))
- k_line = ((x1 - x3) + line_constant*(x2 - x1))/(x4 - x3);
- else
- k_line = ((y1 - y3) + line_constant*(y2 - y1))/(y4 - y3);
-
- if ((k_line > 0.0) && (k_line < 1.0))
- length_ratio = line_constant;
- else
- k_line = 1.0;
- }
- *ratio1 = length_ratio;
- *ratio2 = k_line;
- }
-
- /*
- * Find where (x1, y1) -> (x2, y2) hits one of the lines in xvec, yvec.
- * (*x3, *y3) is the point where it hits.
- *
- */
- void find_end_for_polyline(float n, float xvec[], float yvec[],
- float x1, float y1, float x2, float y2, float *x3, float *y3)
- {
- int i;
- float lastx = xvec[0];
- float lasty = yvec[0];
-
- float min_ratio = 1.0;
- float line_ratio;
- float other_ratio;
-
- for (i = 1; i < n; i++)
- {
- check_line_intersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i],
- &line_ratio, &other_ratio);
- lastx = xvec[i];
- lasty = yvec[i];
-
- if (line_ratio < min_ratio)
- min_ratio = line_ratio;
- }
-
- // Do last (implicit) line if last and first pofloats are not identical
- if (!(xvec[0] == lastx) && (yvec[0] == lasty))
- {
- check_line_intersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0],
- &line_ratio, &other_ratio);
-
- if (line_ratio < min_ratio)
- min_ratio = line_ratio;
- }
-
- *x3 = (x1 + (x2 - x1)*min_ratio);
- *y3 = (y1 + (y2 - y1)*min_ratio);
-
- }
-
- /*
- * Find where the line hits the box.
- *
- */
-
- void find_end_for_box(float width, float height,
- float x1, float y1, // Centre of box (possibly)
- float x2, float y2, // other end of line
- float *x3, float *y3) // End on box edge
- {
- float xvec[5];
- float yvec[5];
-
- xvec[0] = (float)(x1 - width/2.0);
- yvec[0] = (float)(y1 - height/2.0);
- xvec[1] = (float)(x1 - width/2.0);
- yvec[1] = (float)(y1 + height/2.0);
- xvec[2] = (float)(x1 + width/2.0);
- yvec[2] = (float)(y1 + height/2.0);
- xvec[3] = (float)(x1 + width/2.0);
- yvec[3] = (float)(y1 - height/2.0);
- xvec[4] = (float)(x1 - width/2.0);
- yvec[4] = (float)(y1 - height/2.0);
-
- find_end_for_polyline(5, xvec, yvec, x2, y2, x1, y1, x3, y3);
- }
-
- /*
- * Find where the line hits the circle.
- *
- */
-
- void find_end_for_circle(float radius,
- float x1, float y1, // Centre of circle
- float x2, float y2, // Other end of line
- float *x3, float *y3)
- {
- float H = (float)sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
-
- if (H == 0.0)
- {
- *x3 = x1;
- *y3 = y1;
- }
- else
- {
- *y3 = radius * (y2 - y1)/H + y1;
- *x3 = radius * (x2 - x1)/H + x1;
- }
- }
-
- /*
- * Given the line (x1, y1) -> (x2, y2), and an arrow size of given length and width,
- * return the position of the tip of the arrow and the left and right vertices of the arrow.
- *
- */
-
- void get_arrow_points(float x1, float y1, float x2, float y2,
- float length, float width,
- float *tip_x, float *tip_y,
- float *side1_x, float *side1_y,
- float *side2_x, float *side2_y)
- {
- float l = (float)sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
-
- if (l < 0.01)
- l = 0.01;
-
- float i_bar = (x2 - x1)/l;
- float j_bar = (y2 - y1)/l;
-
- float x3 = (- length*i_bar) + x2;
- float y3 = (- length*j_bar) + y2;
-
- *side1_x = width*(-j_bar) + x3;
- *side1_y = width*i_bar + y3;
-
- *side2_x = -width*(-j_bar) + x3;
- *side2_y = -width*i_bar + y3;
-
- *tip_x = x2; *tip_y = y2;
- }
-
- // Update a list item from a list of strings
- void UpdateListBox(wxListBox *item, wxList *list)
- {
- item->Clear();
- if (!list)
- return;
-
- wxNode *node = list->First();
- while (node)
- {
- char *s = (char *)node->Data();
- item->Append(s);
- node = node->Next();
- }
- }
-