X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2bb0cd285ac73fb25396d53f7f52db6f3ca77b63..8ea6ab33e5c58c79d6ed49516ed10c7f6a28bd96:/utils/ogl/src/basic.cpp diff --git a/utils/ogl/src/basic.cpp b/utils/ogl/src/basic.cpp index 6c8add28f9..4faa132925 100644 --- a/utils/ogl/src/basic.cpp +++ b/utils/ogl/src/basic.cpp @@ -24,11 +24,9 @@ #include #endif -#ifdef PROLOGIO #include -#endif -#if USE_IOSTREAMH +#if wxUSE_IOSTREAMH #include #else #include @@ -60,7 +58,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine, wxObject) IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint, wxObject) -wxShapeTextLine::wxShapeTextLine(float the_x, float the_y, const wxString& the_line) +wxShapeTextLine::wxShapeTextLine(double the_x, double the_y, const wxString& the_line) { m_x = the_x; m_y = the_y; m_line = the_line; } @@ -127,13 +125,19 @@ void wxShapeEvtHandler::OnDrawContents(wxDC& dc) m_previousHandler->OnDrawContents(dc); } -void wxShapeEvtHandler::OnSize(float x, float y) +void wxShapeEvtHandler::OnDrawBranches(wxDC& dc, bool erase) +{ + if (m_previousHandler) + m_previousHandler->OnDrawBranches(dc, erase); +} + +void wxShapeEvtHandler::OnSize(double x, double y) { if (m_previousHandler) m_previousHandler->OnSize(x, y); } -bool wxShapeEvtHandler::OnMovePre(wxDC& dc, float x, float y, float old_x, float old_y, bool display) +bool wxShapeEvtHandler::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display) { if (m_previousHandler) return m_previousHandler->OnMovePre(dc, x, y, old_x, old_y, display); @@ -141,7 +145,7 @@ bool wxShapeEvtHandler::OnMovePre(wxDC& dc, float x, float y, float old_x, float return TRUE; } -void wxShapeEvtHandler::OnMovePost(wxDC& dc, float x, float y, float old_x, float old_y, bool display) +void wxShapeEvtHandler::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display) { if (m_previousHandler) m_previousHandler->OnMovePost(dc, x, y, old_x, old_y, display); @@ -165,49 +169,55 @@ void wxShapeEvtHandler::OnHighlight(wxDC& dc) m_previousHandler->OnHighlight(dc); } -void wxShapeEvtHandler::OnLeftClick(float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnLeftClick(double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnLeftClick(x, y, keys, attachment); } -void wxShapeEvtHandler::OnRightClick(float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnLeftDoubleClick(double x, double y, int keys, int attachment) +{ + if (m_previousHandler) + m_previousHandler->OnLeftDoubleClick(x, y, keys, attachment); +} + +void wxShapeEvtHandler::OnRightClick(double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnRightClick(x, y, keys, attachment); } -void wxShapeEvtHandler::OnDragLeft(bool draw, float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnDragLeft(draw, x, y, keys, attachment); } -void wxShapeEvtHandler::OnBeginDragLeft(float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnBeginDragLeft(x, y, keys, attachment); } -void wxShapeEvtHandler::OnEndDragLeft(float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnEndDragLeft(x, y, keys, attachment); } -void wxShapeEvtHandler::OnDragRight(bool draw, float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnDragRight(draw, x, y, keys, attachment); } -void wxShapeEvtHandler::OnBeginDragRight(float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnBeginDragRight(x, y, keys, attachment); } -void wxShapeEvtHandler::OnEndDragRight(float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnEndDragRight(x, y, keys, attachment); @@ -215,25 +225,25 @@ void wxShapeEvtHandler::OnEndDragRight(float x, float y, int keys, int attachmen // Control points ('handles') redirect control to the actual shape, to make it easier // to override sizing behaviour. -void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint* pt, bool draw, float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnSizingDragLeft(pt, draw, x, y, keys, attachment); } -void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint* pt, float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnSizingBeginDragLeft(pt, x, y, keys, attachment); } -void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, float x, float y, int keys, int attachment) +void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment) { if (m_previousHandler) m_previousHandler->OnSizingEndDragLeft(pt, x, y, keys, attachment); } -void wxShapeEvtHandler::OnDrawOutline(wxDC& dc, float x, float y, float w, float h) +void wxShapeEvtHandler::OnDrawOutline(wxDC& dc, double x, double y, double w, double h) { if (m_previousHandler) m_previousHandler->OnDrawOutline(dc, x, y, w, h); @@ -251,6 +261,13 @@ void wxShapeEvtHandler::OnEraseControlPoints(wxDC& dc) m_previousHandler->OnEraseControlPoints(dc); } +// Can override this to prevent or intercept line reordering. +void wxShapeEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering) +{ + if (m_previousHandler) + m_previousHandler->OnChangeAttachment(attachment, line, ordering); +} + IMPLEMENT_ABSTRACT_CLASS(wxShape, wxShapeEvtHandler) wxShape::wxShape(wxShapeCanvas *can) @@ -261,7 +278,7 @@ wxShape::wxShape(wxShapeCanvas *can) m_formatted = FALSE; m_canvas = can; m_xpos = 0.0; m_ypos = 0.0; - m_pen = black_pen; + m_pen = g_oglBlackPen; m_brush = wxWHITE_BRUSH; m_font = g_oglNormalFont; m_textColour = wxBLACK; @@ -269,7 +286,7 @@ wxShape::wxShape(wxShapeCanvas *can) m_visible = FALSE; m_clientData = NULL; m_selected = FALSE; - m_attachmentMode = FALSE; + m_attachmentMode = ATTACHMENT_MODE_NONE; m_spaceAttachments = TRUE; m_disableLabel = FALSE; m_fixedWidth = FALSE; @@ -280,15 +297,20 @@ wxShape::wxShape(wxShapeCanvas *can) m_parent = NULL; m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT; m_shadowMode = SHADOW_NONE; - m_shadowOffsetX = 6.0; - m_shadowOffsetY = 6.0; + m_shadowOffsetX = 6; + m_shadowOffsetY = 6; m_shadowBrush = wxBLACK_BRUSH; - m_textMarginX = 5.0; - m_textMarginY = 5.0; + m_textMarginX = 5; + m_textMarginY = 5; m_regionName = "0"; m_centreResize = TRUE; + m_maintainAspectRatio = FALSE; m_highlighted = FALSE; m_rotation = 0.0; + m_branchNeckLength = 10; + m_branchStemLength = 10; + m_branchSpacing = 10; + m_branchStyle = BRANCHING_ATTACHMENT_NORMAL; // Set up a default region. Much of the above will be put into // the region eventually (the duplication is for compatibility) @@ -509,45 +531,47 @@ void wxShape::SetDefaultRegionSize() wxNode *node = m_regions.First(); if (!node) return; wxShapeRegion *region = (wxShapeRegion *)node->Data(); - float w, h; + double w, h; GetBoundingBoxMin(&w, &h); region->SetSize(w, h); } -bool wxShape::HitTest(float x, float y, int *attachment, float *distance) +bool wxShape::HitTest(double x, double y, int *attachment, double *distance) { // if (!sensitive) // return FALSE; - float width = 0.0, height = 0.0; + double width = 0.0, height = 0.0; GetBoundingBoxMin(&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 + width += (double)4.0; height += (double)4.0; // Allowance for inaccurate mousing - float left = (float)(m_xpos - (width/2.0)); - float top = (float)(m_ypos - (height/2.0)); - float right = (float)(m_xpos + (width/2.0)); - float bottom = (float)(m_ypos + (height/2.0)); + double left = (double)(m_xpos - (width/2.0)); + double top = (double)(m_ypos - (height/2.0)); + double right = (double)(m_xpos + (width/2.0)); + double bottom = (double)(m_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; + double nearest = 999999.0; + + // GetAttachmentPosition[Edge] takes a logical attachment position, + // i.e. if it's rotated through 90%, position 0 is East-facing. for (int i = 0; i < n; i++) { - float xp, yp; - if (GetAttachmentPosition(i, &xp, &yp)) + double xp, yp; + if (GetAttachmentPositionEdge(i, &xp, &yp)) { - float l = (float)sqrt(((xp - x) * (xp - x)) + + double l = (double)sqrt(((xp - x) * (xp - x)) + ((yp - y) * (yp - y))); if (l < nearest) @@ -570,7 +594,7 @@ bool wxShape::HitTest(float x, float y, int *attachment, float *distance) static bool GraphicsInSizeToContents = FALSE; // Infinite recursion elimination void wxShape::FormatText(wxDC& dc, const wxString& s, int i) { - float w, h; + double w, h; ClearText(i); if (m_regions.Number() < 1) @@ -585,26 +609,25 @@ void wxShape::FormatText(wxDC& dc, const wxString& s, int i) region->GetSize(&w, &h); - wxList *string_list = ::FormatText(dc, s, (w-5), (h-5), region->GetFormatMode()); - node = string_list->First(); + wxStringList *stringList = oglFormatText(dc, s, (w-5), (h-5), region->GetFormatMode()); + node = stringList->First(); while (node) { char *s = (char *)node->Data(); wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s); region->GetFormattedText().Append((wxObject *)line); - delete node; - node = string_list->First(); + node = node->Next(); } - delete string_list; - float actualW = w; - float actualH = h; + delete stringList; + double actualW = w; + double actualH = h; // Don't try to resize an object with more than one image (this case should be dealt // with by overriden handlers) if ((region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) && (region->GetFormattedText().Number() > 0) && (m_regions.Number() == 1) && !GraphicsInSizeToContents) { - GetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH); + oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH); if ((actualW+m_textMarginX != w ) || (actualH+m_textMarginY != h)) { // If we are a descendant of a composite, must make sure the composite gets @@ -643,13 +666,13 @@ void wxShape::FormatText(wxDC& dc, const wxString& s, int i) EraseContents(dc); } } - CentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode()); + oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode()); m_formatted = TRUE; } void wxShape::Recentre(wxDC& dc) { - float w, h; + double w, h; GetBoundingBoxMin(&w, &h); int noRegions = m_regions.Number(); @@ -659,14 +682,14 @@ void wxShape::Recentre(wxDC& dc) if (node) { wxShapeRegion *region = (wxShapeRegion *)node->Data(); - CentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, region->GetFormatMode()); + oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, region->GetFormatMode()); } } } -bool wxShape::GetPerimeterPoint(float x1, float y1, - float x2, float y2, - float *x3, float *y3) +bool wxShape::GetPerimeterPoint(double x1, double y1, + double x2, double y2, + double *x3, double *y3) { return FALSE; } @@ -860,8 +883,8 @@ void wxShape::FindRegionNames(wxStringList& list) void wxShape::AssignNewIds() { - if (m_id == 0) - m_id = NewId(); +// if (m_id == 0) + m_id = NewId(); wxNode *node = m_children.First(); while (node) { @@ -892,7 +915,7 @@ void wxShape::OnMoveLinks(wxDC& dc) void wxShape::OnDrawContents(wxDC& dc) { - float bound_x, bound_y; + double bound_x, bound_y; GetBoundingBoxMin(&bound_x, &bound_y); if (m_regions.Number() < 1) return; @@ -905,12 +928,12 @@ void wxShape::OnDrawContents(wxDC& dc) dc.SetBackgroundMode(wxTRANSPARENT); if (!m_formatted) { - CentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode()); + oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode()); m_formatted = TRUE; } if (!GetDisableLabel()) { - DrawFormattedText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode()); + oglDrawFormattedText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x, bound_y, region->GetFormatMode()); } } @@ -919,16 +942,16 @@ void wxShape::DrawContents(wxDC& dc) GetEventHandler()->OnDrawContents(dc); } -void wxShape::OnSize(float x, float y) +void wxShape::OnSize(double x, double y) { } -bool wxShape::OnMovePre(wxDC& dc, float x, float y, float old_x, float old_y, bool display) +bool wxShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display) { return TRUE; } -void wxShape::OnMovePost(wxDC& dc, float x, float y, float old_x, float old_y, bool display) +void wxShape::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display) { } @@ -953,22 +976,22 @@ void wxShape::OnEraseContents(wxDC& dc) if (!m_visible) return; - float maxX, maxY, minX, minY; - float xp = GetX(); - float yp = GetY(); + double maxX, maxY, minX, minY; + double xp = GetX(); + double yp = GetY(); GetBoundingBoxMin(&minX, &minY); GetBoundingBoxMax(&maxX, &maxY); - float topLeftX = (float)(xp - (maxX / 2.0) - 2.0); - float topLeftY = (float)(yp - (maxY / 2.0) - 2.0); + double topLeftX = (double)(xp - (maxX / 2.0) - 2.0); + double topLeftY = (double)(yp - (maxY / 2.0) - 2.0); int penWidth = 0; if (m_pen) penWidth = m_pen->GetWidth(); - dc.SetPen(white_background_pen); - dc.SetBrush(white_background_brush); - dc.DrawRectangle((float)(topLeftX - penWidth), (float)(topLeftY - penWidth), - (float)(maxX + penWidth*2.0 + 4.0), (float)(maxY + penWidth*2.0 + 4.0)); + dc.SetPen(g_oglWhiteBackgroundPen); + dc.SetBrush(g_oglWhiteBackgroundBrush); + dc.DrawRectangle(WXROUND(topLeftX - penWidth), WXROUND(topLeftY - penWidth), + WXROUND(maxX + penWidth*2.0 + 4.0), WXROUND(maxY + penWidth*2.0 + 4.0)); } void wxShape::EraseLinks(wxDC& dc, int attachment, bool recurse) @@ -1024,89 +1047,173 @@ void wxShape::DrawLinks(wxDC& dc, int attachment, bool recurse) } } -void wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move, - float x, float y) +// Returns TRUE if pt1 <= pt2 in the sense that one point comes before another on an +// edge of the shape. +// attachmentPoint is the attachment point (= side) in question. + +// This is the default, rectangular implementation. +bool wxShape::AttachmentSortTest(int attachmentPoint, const wxRealPoint& pt1, const wxRealPoint& pt2) +{ + int physicalAttachment = LogicalToPhysicalAttachment(attachmentPoint); + switch (physicalAttachment) + { + case 0: + case 2: + { + return (pt1.x <= pt2.x) ; + break; + } + case 1: + case 3: + { + return (pt1.y <= pt2.y) ; + break; + } + } + + return FALSE; +} + +bool wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move, + double x, double y) { - int new_point; - float distance; + if (GetAttachmentMode() == ATTACHMENT_MODE_NONE) + return FALSE; + + int newAttachment, oldAttachment; + double 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); + bool hit = HitTest(x, y, &newAttachment, &distance); if (!hit) - return; + return FALSE; EraseLinks(dc); - int old_attachment; if (to_move->GetTo() == this) - old_attachment = to_move->GetAttachmentTo(); + oldAttachment = to_move->GetAttachmentTo(); else - old_attachment = to_move->GetAttachmentFrom(); + oldAttachment = to_move->GetAttachmentFrom(); + + // The links in a new ordering. + wxList newOrdering; + + // First, add all links to the new list. + wxNode *node = m_lines.First(); + while (node) + { + newOrdering.Append(node->Data()); + node = node->Next(); + } // Delete the line object from the list of links; we're going to move // it to another position in the list - m_lines.DeleteObject(to_move); + newOrdering.DeleteObject(to_move); - float old_x = (float) -9999.9; - float old_y = (float) -9999.9; + double old_x = (double) -99999.9; + double old_y = (double) -99999.9; - wxNode *node = m_lines.First(); + node = newOrdering.First(); bool found = FALSE; - while (node && !found) + while (!found && node) { wxLineShape *line = (wxLineShape *)node->Data(); - if ((line->GetTo() == this && old_attachment == line->GetAttachmentTo()) || - (line->GetFrom() == this && old_attachment == line->GetAttachmentFrom())) + if ((line->GetTo() == this && oldAttachment == line->GetAttachmentTo()) || + (line->GetFrom() == this && oldAttachment == line->GetAttachmentFrom())) { - float startX, startY, endX, endY; - float xp, yp; + double startX, startY, endX, endY; + double xp, yp; line->GetEnds(&startX, &startY, &endX, &endY); if (line->GetTo() == this) { -// xp = line->m_xpos2 + line->m_xpos; -// yp = line->m_ypos2 + line->m_ypos; - xp = startX; - yp = startY; - } else - { -// xp = line->m_xpos1 + line->m_xpos; -// yp = line->m_ypos1 + line->m_ypos; xp = endX; yp = endY; + } else + { + xp = startX; + yp = startY; } - switch (old_attachment) + wxRealPoint thisPoint(xp, yp); + wxRealPoint lastPoint(old_x, old_y); + wxRealPoint newPoint(x, y); + + if (AttachmentSortTest(newAttachment, newPoint, thisPoint) && AttachmentSortTest(newAttachment, lastPoint, newPoint)) { - case 0: - case 2: - { - if (x > old_x && x <= xp) - { - found = TRUE; - m_lines.Insert(node, to_move); - } - break; - } - case 1: - case 3: - { - if (y > old_y && y <= yp) - { - found = TRUE; - m_lines.Insert(node, to_move); - } - break; - } + found = TRUE; + newOrdering.Insert(node, to_move); } + old_x = xp; old_y = yp; } node = node->Next(); } + if (!found) - m_lines.Append(to_move); + newOrdering.Append(to_move); + + GetEventHandler()->OnChangeAttachment(newAttachment, to_move, newOrdering); + + return TRUE; +} + +void wxShape::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering) +{ + if (line->GetTo() == this) + line->SetAttachmentTo(attachment); + else + line->SetAttachmentFrom(attachment); + + ApplyAttachmentOrdering(ordering); + + wxClientDC dc(GetCanvas()); + GetCanvas()->PrepareDC(dc); + + MoveLinks(dc); + + if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc); +} + +// Reorders the lines according to the given list. +void wxShape::ApplyAttachmentOrdering(wxList& linesToSort) +{ + // This is a temporary store of all the lines. + wxList linesStore; + + wxNode *node = m_lines.First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + linesStore.Append(line); + node = node->Next();; + } + + m_lines.Clear(); + + node = linesToSort.First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + if (linesStore.Member(line)) + { + // Done this one + linesStore.DeleteObject(line); + m_lines.Append(line); + } + node = node->Next(); + } + + // Now add any lines that haven't been listed in linesToSort. + node = linesStore.First(); + while (node) + { + wxLineShape *line = (wxLineShape *)node->Data(); + m_lines.Append(line); + node = node->Next(); + } } // Reorders the lines coming into the node image at this attachment @@ -1160,12 +1267,12 @@ void wxShape::OnHighlight(wxDC& dc) { } -void wxShape::OnLeftClick(float x, float y, int keys, int attachment) +void wxShape::OnLeftClick(double x, double y, int keys, int attachment) { if ((m_sensitivity & OP_CLICK_LEFT) != OP_CLICK_LEFT) { attachment = 0; - float dist; + double dist; if (m_parent) { m_parent->HitTest(x, y, &attachment, &dist); @@ -1175,12 +1282,12 @@ void wxShape::OnLeftClick(float x, float y, int keys, int attachment) } } -void wxShape::OnRightClick(float x, float y, int keys, int attachment) +void wxShape::OnRightClick(double x, double y, int keys, int attachment) { if ((m_sensitivity & OP_CLICK_RIGHT) != OP_CLICK_RIGHT) { attachment = 0; - float dist; + double dist; if (m_parent) { m_parent->HitTest(x, y, &attachment, &dist); @@ -1190,15 +1297,15 @@ void wxShape::OnRightClick(float x, float y, int keys, int attachment) } } -float DragOffsetX = 0.0; -float DragOffsetY = 0.0; +double DragOffsetX = 0.0; +double DragOffsetY = 0.0; -void wxShape::OnDragLeft(bool draw, float x, float y, int keys, int attachment) +void wxShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment) { if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT) { attachment = 0; - float dist; + double dist; if (m_parent) { m_parent->HitTest(x, y, &attachment, &dist); @@ -1216,23 +1323,23 @@ void wxShape::OnDragLeft(bool draw, float x, float y, int keys, int attachment) dc.SetPen(dottedPen); dc.SetBrush(* wxTRANSPARENT_BRUSH); - float xx, yy; + double xx, yy; xx = x + DragOffsetX; yy = y + DragOffsetY; m_canvas->Snap(&xx, &yy); // m_xpos = xx; m_ypos = yy; - float w, h; + double w, h; GetBoundingBoxMax(&w, &h); GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h); } -void wxShape::OnBeginDragLeft(float x, float y, int keys, int attachment) +void wxShape::OnBeginDragLeft(double x, double y, int keys, int attachment) { if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT) { attachment = 0; - float dist; + double dist; if (m_parent) { m_parent->HitTest(x, y, &attachment, &dist); @@ -1247,8 +1354,10 @@ void wxShape::OnBeginDragLeft(float x, float y, int keys, int attachment) wxClientDC dc(GetCanvas()); GetCanvas()->PrepareDC(dc); - Erase(dc); - float xx, yy; + // New policy: don't erase shape until end of drag. +// Erase(dc); + + double xx, yy; xx = x + DragOffsetX; yy = y + DragOffsetY; m_canvas->Snap(&xx, &yy); @@ -1259,19 +1368,19 @@ void wxShape::OnBeginDragLeft(float x, float y, int keys, int attachment) dc.SetPen(dottedPen); dc.SetBrush((* wxTRANSPARENT_BRUSH)); - float w, h; + double w, h; GetBoundingBoxMax(&w, &h); GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h); m_canvas->CaptureMouse(); } -void wxShape::OnEndDragLeft(float x, float y, int keys, int attachment) +void wxShape::OnEndDragLeft(double x, double y, int keys, int attachment) { m_canvas->ReleaseMouse(); if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT) { attachment = 0; - float dist; + double dist; if (m_parent) { m_parent->HitTest(x, y, &attachment, &dist); @@ -1285,20 +1394,24 @@ void wxShape::OnEndDragLeft(float x, float y, int keys, int attachment) dc.SetLogicalFunction(wxCOPY); - float xx = x + DragOffsetX; - float yy = y + DragOffsetY; + double xx = x + DragOffsetX; + double yy = y + DragOffsetY; m_canvas->Snap(&xx, &yy); // canvas->Snap(&m_xpos, &m_ypos); + + // New policy: erase shape at end of drag. + Erase(dc); + Move(dc, xx, yy); if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc); } -void wxShape::OnDragRight(bool draw, float x, float y, int keys, int attachment) +void wxShape::OnDragRight(bool draw, double x, double y, int keys, int attachment) { if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT) { attachment = 0; - float dist; + double dist; if (m_parent) { m_parent->HitTest(x, y, &attachment, &dist); @@ -1308,12 +1421,12 @@ void wxShape::OnDragRight(bool draw, float x, float y, int keys, int attachment) } } -void wxShape::OnBeginDragRight(float x, float y, int keys, int attachment) +void wxShape::OnBeginDragRight(double x, double y, int keys, int attachment) { if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT) { attachment = 0; - float dist; + double dist; if (m_parent) { m_parent->HitTest(x, y, &attachment, &dist); @@ -1323,12 +1436,12 @@ void wxShape::OnBeginDragRight(float x, float y, int keys, int attachment) } } -void wxShape::OnEndDragRight(float x, float y, int keys, int attachment) +void wxShape::OnEndDragRight(double x, double y, int keys, int attachment) { if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT) { attachment = 0; - float dist; + double dist; if (m_parent) { m_parent->HitTest(x, y, &attachment, &dist); @@ -1338,23 +1451,23 @@ void wxShape::OnEndDragRight(float x, float y, int keys, int attachment) } } -void wxShape::OnDrawOutline(wxDC& dc, float x, float y, float w, float h) +void wxShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h) { - float top_left_x = (float)(x - w/2.0); - float top_left_y = (float)(y - h/2.0); - float top_right_x = (float)(top_left_x + w); - float top_right_y = (float)top_left_y; - float bottom_left_x = (float)top_left_x; - float bottom_left_y = (float)(top_left_y + h); - float bottom_right_x = (float)top_right_x; - float bottom_right_y = (float)bottom_left_y; + double top_left_x = (double)(x - w/2.0); + double top_left_y = (double)(y - h/2.0); + double top_right_x = (double)(top_left_x + w); + double top_right_y = (double)top_left_y; + double bottom_left_x = (double)top_left_x; + double bottom_left_y = (double)(top_left_y + h); + double bottom_right_x = (double)top_right_x; + double bottom_right_y = (double)bottom_left_y; wxPoint points[5]; - points[0].x = top_left_x; points[0].y = top_left_y; - points[1].x = top_right_x; points[1].y = top_right_y; - points[2].x = bottom_right_x; points[2].y = bottom_right_y; - points[3].x = bottom_left_x; points[3].y = bottom_left_y; - points[4].x = top_left_x; points[4].y = top_left_y; + points[0].x = WXROUND(top_left_x); points[0].y = WXROUND(top_left_y); + points[1].x = WXROUND(top_right_x); points[1].y = WXROUND(top_right_y); + points[2].x = WXROUND(bottom_right_x); points[2].y = WXROUND(bottom_right_y); + points[3].x = WXROUND(bottom_left_x); points[3].y = WXROUND(bottom_left_y); + points[4].x = WXROUND(top_left_x); points[4].y = WXROUND(top_left_y); dc.DrawLines(5, points); } @@ -1369,20 +1482,20 @@ void wxShape::Detach() m_canvas = NULL; } -void wxShape::Move(wxDC& dc, float x, float y, bool display) +void wxShape::Move(wxDC& dc, double x, double y, bool display) { - float old_x = m_xpos; - float old_y = m_ypos; - - m_xpos = x; m_ypos = y; + double old_x = m_xpos; + double old_y = m_ypos; if (!GetEventHandler()->OnMovePre(dc, x, y, old_x, old_y, display)) { - m_xpos = old_x; - m_ypos = old_y; +// m_xpos = old_x; +// m_ypos = old_y; return; } + m_xpos = x; m_ypos = y; + ResetControlPoints(); if (display) @@ -1406,6 +1519,7 @@ void wxShape::Draw(wxDC& dc) GetEventHandler()->OnDraw(dc); GetEventHandler()->OnDrawContents(dc); GetEventHandler()->OnDrawControlPoints(dc); + GetEventHandler()->OnDrawBranches(dc); } } @@ -1439,6 +1553,7 @@ void wxShape::Erase(wxDC& dc) { GetEventHandler()->OnErase(dc); GetEventHandler()->OnEraseControlPoints(dc); + GetEventHandler()->OnDrawBranches(dc, TRUE); } void wxShape::EraseContents(wxDC& dc) @@ -1460,17 +1575,17 @@ void wxShape::AddText(const wxString& string) m_formatted = FALSE; } -void wxShape::SetSize(float x, float y, bool recursive) +void wxShape::SetSize(double x, double y, bool recursive) { SetAttachmentSize(x, y); SetDefaultRegionSize(); } -void wxShape::SetAttachmentSize(float w, float h) +void wxShape::SetAttachmentSize(double w, double h) { - float scaleX; - float scaleY; - float width, height; + double scaleX; + double scaleY; + double width, height; GetBoundingBoxMin(&width, &height); if (width == 0.0) scaleX = 1.0; @@ -1483,25 +1598,88 @@ void wxShape::SetAttachmentSize(float w, float h) while (node) { wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); - point->m_x = (float)(point->m_x * scaleX); - point->m_y = (float)(point->m_y * scaleY); + point->m_x = (double)(point->m_x * scaleX); + point->m_y = (double)(point->m_y * scaleY); node = node->Next(); } } // Add line FROM this object void wxShape::AddLine(wxLineShape *line, wxShape *other, - int attachFrom, int attachTo) + int attachFrom, int attachTo, + // The line ordering + int positionFrom, int positionTo) { - if (!m_lines.Member(line)) - m_lines.Append(line); + if (positionFrom == -1) + { + if (!m_lines.Member(line)) + m_lines.Append(line); + } + else + { + // Don't preserve old ordering if we have new ordering instructions + m_lines.DeleteObject(line); + if (positionFrom < m_lines.Number()) + { + wxNode* node = m_lines.Nth(positionFrom); + m_lines.Insert(node, line); + } + else + m_lines.Append(line); + } - if (!other->m_lines.Member(line)) - other->m_lines.Append(line); + if (positionTo == -1) + { + if (!other->m_lines.Member(line)) + other->m_lines.Append(line); + } + else + { + // Don't preserve old ordering if we have new ordering instructions + other->m_lines.DeleteObject(line); + if (positionTo < other->m_lines.Number()) + { + wxNode* node = other->m_lines.Nth(positionTo); + other->m_lines.Insert(node, line); + } + else + other->m_lines.Append(line); + } +#if 0 + // Wrong: doesn't preserve ordering of shape already linked + m_lines.DeleteObject(line); + other->m_lines.DeleteObject(line); - line->SetFrom(this); - line->SetTo(other); - line->SetAttachments(attachFrom, attachTo); + if (positionFrom == -1) + m_lines.Append(line); + else + { + if (positionFrom < m_lines.Number()) + { + wxNode* node = m_lines.Nth(positionFrom); + m_lines.Insert(node, line); + } + else + m_lines.Append(line); + } + + if (positionTo == -1) + other->m_lines.Append(line); + else + { + if (positionTo < other->m_lines.Number()) + { + wxNode* node = other->m_lines.Nth(positionTo); + other->m_lines.Insert(node, line); + } + else + other->m_lines.Append(line); + } +#endif + + line->SetFrom(this); + line->SetTo(other); + line->SetAttachments(attachFrom, attachTo); } void wxShape::RemoveLine(wxLineShape *line) @@ -1515,12 +1693,7 @@ void wxShape::RemoveLine(wxLineShape *line) } #ifdef PROLOGIO -char *wxShape::GetFunctor() -{ - return "node_image"; -} - -void wxShape::WritePrologAttributes(wxExpr *clause) +void wxShape::WriteAttributes(wxExpr *clause) { clause->AddAttributeValueString("type", GetClassInfo()->GetClassName()); clause->AddAttributeValue("id", m_id); @@ -1535,7 +1708,13 @@ void wxShape::WritePrologAttributes(wxExpr *clause) clause->AddAttributeValue("pen_style", (long)penStyle); wxString penColour = wxTheColourDatabase->FindName(m_pen->GetColour()); - if ((penColour != "") && (penColour != "BLACK")) + if (penColour == "") + { + wxString hex(oglColourToHex(m_pen->GetColour())); + hex = wxString("#") + hex; + clause->AddAttributeValueString("pen_colour", hex); + } + else if (penColour != "BLACK") clause->AddAttributeValueString("pen_colour", penColour); } @@ -1543,7 +1722,13 @@ void wxShape::WritePrologAttributes(wxExpr *clause) { wxString brushColour = wxTheColourDatabase->FindName(m_brush->GetColour()); - if ((brushColour != "") && (brushColour != "WHITE")) + if (brushColour == "") + { + wxString hex(oglColourToHex(m_brush->GetColour())); + hex = wxString("#") + hex; + clause->AddAttributeValueString("brush_colour", hex); + } + else if (brushColour != "WHITE") clause->AddAttributeValueString("brush_colour", brushColour); if (m_brush->GetStyle() != wxSOLID) @@ -1555,7 +1740,7 @@ void wxShape::WritePrologAttributes(wxExpr *clause) int n_lines = m_lines.Number(); if (n_lines > 0) { - wxExpr *list = new wxExpr(PrologList); + wxExpr *list = new wxExpr(wxExprList); wxNode *node = m_lines.First(); while (node) { @@ -1582,6 +1767,7 @@ void wxShape::WritePrologAttributes(wxExpr *clause) clause->AddAttributeValue("shadow_mode", (long)m_shadowMode); if (m_centreResize != TRUE) clause->AddAttributeValue("centre_resize", (long)0); + clause->AddAttributeValue("maintain_aspect_ratio", (long) m_maintainAspectRatio); if (m_highlighted != FALSE) clause->AddAttributeValue("hilite", (long)m_highlighted); @@ -1591,15 +1777,23 @@ void wxShape::WritePrologAttributes(wxExpr *clause) if (m_rotation != 0.0) clause->AddAttributeValue("rotation", m_rotation); + if (!this->IsKindOf(CLASSINFO(wxLineShape))) + { + clause->AddAttributeValue("neck_length", (long) m_branchNeckLength); + clause->AddAttributeValue("stem_length", (long) m_branchStemLength); + clause->AddAttributeValue("branch_spacing", (long) m_branchSpacing); + clause->AddAttributeValue("branch_style", (long) m_branchStyle); + } + // Write user-defined attachment points, if any if (m_attachmentPoints.Number() > 0) { - wxExpr *attachmentList = new wxExpr(PrologList); + wxExpr *attachmentList = new wxExpr(wxExprList); wxNode *node = m_attachmentPoints.First(); while (node) { wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); - wxExpr *pointExpr = new wxExpr(PrologList); + wxExpr *pointExpr = new wxExpr(wxExprList); pointExpr->Append(new wxExpr((long)point->m_id)); pointExpr->Append(new wxExpr(point->m_x)); pointExpr->Append(new wxExpr(point->m_y)); @@ -1630,9 +1824,9 @@ void wxShape::WriteRegions(wxExpr *clause) // Original text and region attributes: // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY // formatMode fontSize fontFamily fontStyle fontWeight textColour) - wxExpr *regionExpr = new wxExpr(PrologList); - regionExpr->Append(new wxExpr(PrologString, (region->m_regionName ? region->m_regionName : ""))); - regionExpr->Append(new wxExpr(PrologString, (region->m_regionText ? region->m_regionText : ""))); + wxExpr *regionExpr = new wxExpr(wxExprList); + regionExpr->Append(new wxExpr(wxExprString, region->m_regionName)); + regionExpr->Append(new wxExpr(wxExprString, region->m_regionText)); regionExpr->Append(new wxExpr(region->m_x)); regionExpr->Append(new wxExpr(region->m_y)); @@ -1650,24 +1844,24 @@ void wxShape::WriteRegions(wxExpr *clause) regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetFamily() : wxDEFAULT))); regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetStyle() : wxDEFAULT))); regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetWeight() : wxNORMAL))); - regionExpr->Append(new wxExpr(PrologString, region->m_textColour ? region->m_textColour : "BLACK")); + regionExpr->Append(new wxExpr(wxExprString, region->m_textColour)); // New members for pen colour/style - regionExpr->Append(new wxExpr(PrologString, region->m_penColour ? region->m_penColour : "BLACK")); + regionExpr->Append(new wxExpr(wxExprString, region->m_penColour)); regionExpr->Append(new wxExpr((long)region->m_penStyle)); // Formatted text: // text1 = ((x y string) (x y string) ...) - wxExpr *textExpr = new wxExpr(PrologList); + wxExpr *textExpr = new wxExpr(wxExprList); wxNode *textNode = region->m_formattedText.First(); while (textNode) { wxShapeTextLine *line = (wxShapeTextLine *)textNode->Data(); - wxExpr *list2 = new wxExpr(PrologList); + wxExpr *list2 = new wxExpr(wxExprList); list2->Append(new wxExpr(line->GetX())); list2->Append(new wxExpr(line->GetY())); - list2->Append(new wxExpr(PrologString, line->GetText())); + list2->Append(new wxExpr(wxExprString, line->GetText())); textExpr->Append(list2); textNode = textNode->Next(); } @@ -1681,7 +1875,7 @@ void wxShape::WriteRegions(wxExpr *clause) } } -void wxShape::ReadPrologAttributes(wxExpr *clause) +void wxShape::ReadAttributes(wxExpr *clause) { clause->GetAttributeValue("id", m_id); RegisterId(m_id); @@ -1692,42 +1886,42 @@ void wxShape::ReadPrologAttributes(wxExpr *clause) // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.) ClearText(); wxExpr *strings = clause->AttributeValue("text"); - if (strings && strings->Type() == PrologList) + if (strings && strings->Type() == wxExprList) { m_formatted = TRUE; // Assume text is formatted unless we prove otherwise wxExpr *node = strings->value.first; while (node) { wxExpr *string_expr = node; - float the_x = 0.0; - float the_y = 0.0; + double the_x = 0.0; + double the_y = 0.0; wxString the_string(""); // string_expr can either be a string, or a list of // 3 elements: x, y, and string. - if (string_expr->Type() == PrologString) + if (string_expr->Type() == wxExprString) { the_string = string_expr->StringValue(); m_formatted = FALSE; } - else if (string_expr->Type() == PrologList) + else if (string_expr->Type() == wxExprList) { wxExpr *first = string_expr->value.first; - wxExpr *second = first ? first->next : NULL; - wxExpr *third = second ? second->next : NULL; + wxExpr *second = first ? first->next : (wxExpr*) NULL; + wxExpr *third = second ? second->next : (wxExpr*) NULL; if (first && second && third && - (first->Type() == PrologReal || first->Type() == PrologInteger) && - (second->Type() == PrologReal || second->Type() == PrologInteger) && - third->Type() == PrologString) + (first->Type() == wxExprReal || first->Type() == wxExprInteger) && + (second->Type() == wxExprReal || second->Type() == wxExprInteger) && + third->Type() == wxExprString) { - if (first->Type() == PrologReal) + if (first->Type() == wxExprReal) the_x = first->RealValue(); - else the_x = (float)first->IntegerValue(); + else the_x = (double)first->IntegerValue(); - if (second->Type() == PrologReal) + if (second->Type() == wxExprReal) the_y = second->RealValue(); - else the_y = (float)second->IntegerValue(); + else the_y = (double)second->IntegerValue(); the_string = third->StringValue(); } @@ -1745,7 +1939,7 @@ void wxShape::ReadPrologAttributes(wxExpr *clause) int pen_width = 1; int pen_style = wxSOLID; int brush_style = wxSOLID; - m_attachmentMode = FALSE; + m_attachmentMode = ATTACHMENT_MODE_NONE; clause->GetAttributeValue("pen_colour", pen_string); clause->GetAttributeValue("text_colour", m_textColourName); @@ -1761,7 +1955,7 @@ void wxShape::ReadPrologAttributes(wxExpr *clause) int iVal = (int) m_attachmentMode; clause->GetAttributeValue("use_attachments", iVal); - m_attachmentMode = (iVal != 0); + m_attachmentMode = iVal; clause->GetAttributeValue("sensitivity", m_sensitivity); @@ -1780,10 +1974,28 @@ void wxShape::ReadPrologAttributes(wxExpr *clause) clause->GetAttributeValue("format_mode", m_formatMode); clause->GetAttributeValue("shadow_mode", m_shadowMode); + iVal = m_branchNeckLength; + clause->GetAttributeValue("neck_length", iVal); + m_branchNeckLength = iVal; + + iVal = m_branchStemLength; + clause->GetAttributeValue("stem_length", iVal); + m_branchStemLength = iVal; + + iVal = m_branchSpacing; + clause->GetAttributeValue("branch_spacing", iVal); + m_branchSpacing = iVal; + + clause->GetAttributeValue("branch_style", m_branchStyle); + iVal = (int) m_centreResize; clause->GetAttributeValue("centre_resize", iVal); m_centreResize = (iVal != 0); + iVal = (int) m_maintainAspectRatio; + clause->GetAttributeValue("maintain_aspect_ratio", iVal); + m_maintainAspectRatio = (iVal != 0); + iVal = (int) m_highlighted; clause->GetAttributeValue("hilite", iVal); m_highlighted = (iVal != 0); @@ -1795,17 +2007,31 @@ void wxShape::ReadPrologAttributes(wxExpr *clause) if (brush_string == "") brush_string = "WHITE"; - m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style); + if (pen_string[0] == '#') + { + wxColour col(oglHexToColour(pen_string.After('#'))); + m_pen = wxThePenList->FindOrCreatePen(col, pen_width, pen_style); + } + else + m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style); + if (!m_pen) m_pen = wxBLACK_PEN; - m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style); + if (brush_string[0] == '#') + { + wxColour col(oglHexToColour(brush_string.After('#'))); + m_brush = wxTheBrushList->FindOrCreateBrush(col, brush_style); + } + else + m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style); + if (!m_brush) m_brush = wxWHITE_BRUSH; int point_size = 10; clause->GetAttributeValue("point_size", point_size); - SetFont(MatchFont(point_size)); + SetFont(oglMatchFont(point_size)); // Read user-defined attachment points, if any wxExpr *attachmentList = clause->AttributeValue("user_attachments"); @@ -1850,7 +2076,7 @@ void wxShape::ReadRegions(wxExpr *clause) m_formatted = TRUE; // Assume text is formatted unless we prove otherwise - while (regionExpr = clause->AttributeValue(regionNameBuf)) + while ((regionExpr = clause->AttributeValue(regionNameBuf))) { /* * Get the region information @@ -1859,14 +2085,14 @@ void wxShape::ReadRegions(wxExpr *clause) wxString regionName(""); wxString regionText(""); - float x = 0.0; - float y = 0.0; - float width = 0.0; - float height = 0.0; - float minWidth = 5.0; - float minHeight = 5.0; - float m_regionProportionX = -1.0; - float m_regionProportionY = -1.0; + double x = 0.0; + double y = 0.0; + double width = 0.0; + double height = 0.0; + double minWidth = 5.0; + double minHeight = 5.0; + double m_regionProportionX = -1.0; + double m_regionProportionY = -1.0; int formatMode = FORMAT_NONE; int fontSize = 10; int fontFamily = wxSWISS; @@ -1876,7 +2102,7 @@ void wxShape::ReadRegions(wxExpr *clause) wxString penColour(""); int penStyle = wxSOLID; - if (regionExpr->Type() == PrologList) + if (regionExpr->Type() == wxExprList) { wxExpr *nameExpr = regionExpr->Nth(0); wxExpr *textExpr = regionExpr->Nth(1); @@ -1954,41 +2180,41 @@ void wxShape::ReadRegions(wxExpr *clause) * */ textExpr = clause->AttributeValue(textNameBuf); - if (textExpr && (textExpr->Type() == PrologList)) + if (textExpr && (textExpr->Type() == wxExprList)) { wxExpr *node = textExpr->value.first; while (node) { wxExpr *string_expr = node; - float the_x = 0.0; - float the_y = 0.0; + double the_x = 0.0; + double the_y = 0.0; wxString the_string(""); // string_expr can either be a string, or a list of // 3 elements: x, y, and string. - if (string_expr->Type() == PrologString) + if (string_expr->Type() == wxExprString) { the_string = string_expr->StringValue(); m_formatted = FALSE; } - else if (string_expr->Type() == PrologList) + else if (string_expr->Type() == wxExprList) { wxExpr *first = string_expr->value.first; - wxExpr *second = first ? first->next : NULL; - wxExpr *third = second ? second->next : NULL; + wxExpr *second = first ? first->next : (wxExpr*) NULL; + wxExpr *third = second ? second->next : (wxExpr*) NULL; if (first && second && third && - (first->Type() == PrologReal || first->Type() == PrologInteger) && - (second->Type() == PrologReal || second->Type() == PrologInteger) && - third->Type() == PrologString) + (first->Type() == wxExprReal || first->Type() == wxExprInteger) && + (second->Type() == wxExprReal || second->Type() == wxExprInteger) && + third->Type() == wxExprString) { - if (first->Type() == PrologReal) + if (first->Type() == wxExprReal) the_x = first->RealValue(); - else the_x = (float)first->IntegerValue(); + else the_x = (double)first->IntegerValue(); - if (second->Type() == PrologReal) + if (second->Type() == wxExprReal) the_y = second->RealValue(); - else the_y = (float)second->IntegerValue(); + else the_y = (double)second->IntegerValue(); the_string = third->StringValue(); } @@ -2045,6 +2271,7 @@ void wxShape::Copy(wxShape& copy) copy.m_brush = m_brush; copy.m_textColour = m_textColour; copy.m_centreResize = m_centreResize; + copy.m_maintainAspectRatio = m_maintainAspectRatio; copy.m_attachmentMode = m_attachmentMode; copy.m_spaceAttachments = m_spaceAttachments; copy.m_highlighted = m_highlighted; @@ -2065,6 +2292,10 @@ void wxShape::Copy(wxShape& copy) copy.m_shadowOffsetY = m_shadowOffsetY; copy.m_shadowBrush = m_shadowBrush; + copy.m_branchNeckLength = m_branchNeckLength; + copy.m_branchStemLength = m_branchStemLength; + copy.m_branchSpacing = m_branchSpacing; + // Copy text regions copy.ClearRegions(); wxNode *node = m_regions.First(); @@ -2089,13 +2320,23 @@ void wxShape::Copy(wxShape& copy) copy.m_attachmentPoints.Append((wxObject *)newPoint); node = node->Next(); } + + // Copy lines + copy.m_lines.Clear(); + node = m_lines.First(); + while (node) + { + wxLineShape* line = (wxLineShape*) node->Data(); + copy.m_lines.Append(line); + node = node->Next(); + } } // Create and return a new, fully copied object. wxShape *wxShape::CreateNewCopy(bool resetMapping, bool recompute) { if (resetMapping) - wxObjectCopyMapping.Clear(); + oglObjectCopyMapping.Clear(); wxShape* newObject = (wxShape*) GetClassInfo()->CreateObject(); @@ -2108,8 +2349,8 @@ wxShape *wxShape::CreateNewCopy(bool resetMapping, bool recompute) { wxShapeEvtHandler* newHandler = GetEventHandler()->CreateNewCopy(); newObject->SetEventHandler(newHandler); - newObject->SetPreviousHandler(newObject); - newHandler->SetPreviousHandler(newHandler); + newObject->SetPreviousHandler(NULL); + newHandler->SetPreviousHandler(newObject); newHandler->SetShape(newObject); } @@ -2137,19 +2378,19 @@ void wxShape::CopyWithHandler(wxShape& copy) // Default - make 6 control points void wxShape::MakeControlPoints() { - float maxX, maxY, minX, minY; + double maxX, maxY, minX, minY; GetBoundingBoxMax(&maxX, &maxY); GetBoundingBoxMin(&minX, &minY); - float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2); - float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2); + double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2); + double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2); // Offsets from main object - float top = (float)(- (heightMin / 2.0)); - float bottom = (float)(heightMin / 2.0 + (maxY - minY)); - float left = (float)(- (widthMin / 2.0)); - float right = (float)(widthMin / 2.0 + (maxX - minX)); + double top = (double)(- (heightMin / 2.0)); + double bottom = (double)(heightMin / 2.0 + (maxY - minY)); + double left = (double)(- (widthMin / 2.0)); + double right = (double)(widthMin / 2.0 + (maxX - minX)); wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top, CONTROL_POINT_DIAGONAL); @@ -2222,19 +2463,19 @@ void wxShape::ResetControlPoints() if (m_controlPoints.Number() < 1) return; - float maxX, maxY, minX, minY; + double maxX, maxY, minX, minY; GetBoundingBoxMax(&maxX, &maxY); GetBoundingBoxMin(&minX, &minY); - float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2); - float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2); + double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2); + double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2); // Offsets from main object - float top = (float)(- (heightMin / 2.0)); - float bottom = (float)(heightMin / 2.0 + (maxY - minY)); - float left = (float)(- (widthMin / 2.0)); - float right = (float)(widthMin / 2.0 + (maxX - minX)); + double top = (double)(- (heightMin / 2.0)); + double bottom = (double)(heightMin / 2.0 + (maxY - minY)); + double left = (double)(- (widthMin / 2.0)); + double right = (double)(widthMin / 2.0 + (maxX - minX)); wxNode *node = m_controlPoints.First(); wxControlPoint *control = (wxControlPoint *)node->Data(); @@ -2392,7 +2633,7 @@ bool wxShape::AncestorSelected() const return GetParent()->AncestorSelected(); } -int wxShape::GetNumberOfAttachments() +int wxShape::GetNumberOfAttachments() const { // Should return the MAXIMUM attachment point id here, // so higher-level functions can iterate through all attachments, @@ -2414,10 +2655,12 @@ int wxShape::GetNumberOfAttachments() } } -bool wxShape::AttachmentIsValid(int attachment) +bool wxShape::AttachmentIsValid(int attachment) const { - if ((attachment >= 0) && (attachment < 4)) - return TRUE; + if (m_attachmentPoints.Number() == 0) + { + return ((attachment >= 0) && (attachment < 4)) ; + } wxNode *node = m_attachmentPoints.First(); while (node) @@ -2430,36 +2673,105 @@ bool wxShape::AttachmentIsValid(int attachment) return FALSE; } -bool wxShape::GetAttachmentPosition(int attachment, float *x, float *y, +bool wxShape::GetAttachmentPosition(int attachment, double *x, double *y, int nth, int no_arcs, wxLineShape *line) { - if (!m_attachmentMode) - { - *x = m_xpos; *y = m_ypos; - return TRUE; - } - else - { - wxNode *node = m_attachmentPoints.First(); - while (node) + if (m_attachmentMode == ATTACHMENT_MODE_NONE) { - wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); - if (point->m_id == attachment) - { - *x = (float)(m_xpos + point->m_x); - *y = (float)(m_ypos + point->m_y); + *x = m_xpos; *y = m_ypos; + return TRUE; + } + else if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING) + { + wxRealPoint pt, stemPt; + GetBranchingAttachmentPoint(attachment, nth, pt, stemPt); + *x = pt.x; + *y = pt.y; return TRUE; - } - node = node->Next(); } - *x = m_xpos; *y = m_ypos; + else if (m_attachmentMode == ATTACHMENT_MODE_EDGE) + { + if (m_attachmentPoints.Number() > 0) + { + wxNode *node = m_attachmentPoints.First(); + while (node) + { + wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data(); + if (point->m_id == attachment) + { + *x = (double)(m_xpos + point->m_x); + *y = (double)(m_ypos + point->m_y); + return TRUE; + } + node = node->Next(); + } + *x = m_xpos; *y = m_ypos; + return FALSE; + } + else + { + // Assume is rectangular + double w, h; + GetBoundingBoxMax(&w, &h); + double top = (double)(m_ypos + h/2.0); + double bottom = (double)(m_ypos - h/2.0); + double left = (double)(m_xpos - w/2.0); + double right = (double)(m_xpos + w/2.0); + + bool isEnd = (line && line->IsEnd(this)); + + int physicalAttachment = LogicalToPhysicalAttachment(attachment); + + // Simplified code + switch (physicalAttachment) + { + case 0: + { + wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(right, bottom), + nth, no_arcs, line); + + *x = pt.x; *y = pt.y; + break; + } + case 1: + { + wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(right, bottom), wxRealPoint(right, top), + nth, no_arcs, line); + + *x = pt.x; *y = pt.y; + break; + } + case 2: + { + wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, top), wxRealPoint(right, top), + nth, no_arcs, line); + + *x = pt.x; *y = pt.y; + break; + } + case 3: + { + wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(left, top), + nth, no_arcs, line); + + *x = pt.x; *y = pt.y; + break; + } + default: + { + return FALSE; + break; + } + } + return TRUE; + } + } return FALSE; - } } -void wxShape::GetBoundingBoxMax(float *w, float *h) +void wxShape::GetBoundingBoxMax(double *w, double *h) { - float ww, hh; + double ww, hh; GetBoundingBoxMin(&ww, &hh); if (m_shadowMode != SHADOW_NONE) { @@ -2501,3 +2813,462 @@ void wxShape::ClearPointList(wxList& list) list.Clear(); } +// Assuming the attachment lies along a vertical or horizontal line, +// calculate the position on that point. +wxRealPoint wxShape::CalcSimpleAttachment(const wxRealPoint& pt1, const wxRealPoint& pt2, + int nth, int noArcs, wxLineShape* line) +{ + bool isEnd = (line && line->IsEnd(this)); + + // Are we horizontal or vertical? + bool isHorizontal = (oglRoughlyEqual(pt1.y, pt2.y) == TRUE); + + double x, y; + + if (isHorizontal) + { + wxRealPoint firstPoint, secondPoint; + if (pt1.x > pt2.x) + { + firstPoint = pt2; + secondPoint = pt1; + } + else + { + firstPoint = pt1; + secondPoint = pt2; + } + + if (m_spaceAttachments) + { + if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE)) + { + // Align line according to the next handle along + wxRealPoint *point = line->GetNextControlPoint(this); + if (point->x < firstPoint.x) + x = firstPoint.x; + else if (point->x > secondPoint.x) + x = secondPoint.x; + else + x = point->x; + } + else + x = firstPoint.x + (nth + 1)*(secondPoint.x - firstPoint.x)/(noArcs + 1); + } + else x = (secondPoint.x - firstPoint.x)/2.0; // Midpoint + + y = pt1.y; + } + else + { + wxASSERT( oglRoughlyEqual(pt1.x, pt2.x) == TRUE ); + + wxRealPoint firstPoint, secondPoint; + if (pt1.y > pt2.y) + { + firstPoint = pt2; + secondPoint = pt1; + } + else + { + firstPoint = pt1; + secondPoint = pt2; + } + + if (m_spaceAttachments) + { + if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE)) + { + // Align line according to the next handle along + wxRealPoint *point = line->GetNextControlPoint(this); + if (point->y < firstPoint.y) + y = firstPoint.y; + else if (point->y > secondPoint.y) + y = secondPoint.y; + else + y = point->y; + } + else + y = firstPoint.y + (nth + 1)*(secondPoint.y - firstPoint.y)/(noArcs + 1); + } + else y = (secondPoint.y - firstPoint.y)/2.0; // Midpoint + + x = pt1.x; + } + + return wxRealPoint(x, y); +} + +// Return the zero-based position in m_lines of line. +int wxShape::GetLinePosition(wxLineShape* line) +{ + int i = 0; + for (i = 0; i < m_lines.Number(); i++) + if ((wxLineShape*) (m_lines.Nth(i)->Data()) == line) + return i; + + return 0; +} + +// +// |________| +// | <- root +// | <- neck +// shoulder1 ->---------<- shoulder2 +// | | | | | +// <- branching attachment point N-1 + +// This function gets information about where branching connections go. +// Returns FALSE if there are no lines at this attachment. +bool wxShape::GetBranchingAttachmentInfo(int attachment, wxRealPoint& root, wxRealPoint& neck, + wxRealPoint& shoulder1, wxRealPoint& shoulder2) +{ + int physicalAttachment = LogicalToPhysicalAttachment(attachment); + + // Number of lines at this attachment. + int lineCount = GetAttachmentLineCount(attachment); + + if (lineCount == 0) + return FALSE; + + int totalBranchLength = m_branchSpacing * (lineCount - 1); + + root = GetBranchingAttachmentRoot(attachment); + + // Assume that we have attachment points 0 to 3: top, right, bottom, left. + switch (physicalAttachment) + { + case 0: + { + neck.x = GetX(); + neck.y = root.y - m_branchNeckLength; + + shoulder1.x = root.x - (totalBranchLength/2.0) ; + shoulder2.x = root.x + (totalBranchLength/2.0) ; + + shoulder1.y = neck.y; + shoulder2.y = neck.y; + break; + } + case 1: + { + neck.x = root.x + m_branchNeckLength; + neck.y = root.y; + + shoulder1.x = neck.x ; + shoulder2.x = neck.x ; + + shoulder1.y = neck.y - (totalBranchLength/2.0) ; + shoulder2.y = neck.y + (totalBranchLength/2.0) ; + break; + } + case 2: + { + neck.x = GetX(); + neck.y = root.y + m_branchNeckLength; + + shoulder1.x = root.x - (totalBranchLength/2.0) ; + shoulder2.x = root.x + (totalBranchLength/2.0) ; + + shoulder1.y = neck.y; + shoulder2.y = neck.y; + break; + } + case 3: + { + neck.x = root.x - m_branchNeckLength; + neck.y = root.y ; + + shoulder1.x = neck.x ; + shoulder2.x = neck.x ; + + shoulder1.y = neck.y - (totalBranchLength/2.0) ; + shoulder2.y = neck.y + (totalBranchLength/2.0) ; + break; + } + default: + { + wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentInfo." ); + break; + } + } + return TRUE; +} + +// n is the number of the adjoining line, from 0 to N-1 where N is the number of lines +// at this attachment point. +// Get the attachment point where the arc joins the stem, and also the point where the +// the stem meets the shoulder. +bool wxShape::GetBranchingAttachmentPoint(int attachment, int n, wxRealPoint& pt, wxRealPoint& stemPt) +{ + int physicalAttachment = LogicalToPhysicalAttachment(attachment); + + wxRealPoint root, neck, shoulder1, shoulder2; + GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2); + + // Assume that we have attachment points 0 to 3: top, right, bottom, left. + switch (physicalAttachment) + { + case 0: + { + pt.y = neck.y - m_branchStemLength; + pt.x = shoulder1.x + n*m_branchSpacing; + + stemPt.x = pt.x; + stemPt.y = neck.y; + break; + } + case 2: + { + pt.y = neck.y + m_branchStemLength; + pt.x = shoulder1.x + n*m_branchSpacing; + + stemPt.x = pt.x; + stemPt.y = neck.y; + break; + } + case 1: + { + pt.x = neck.x + m_branchStemLength; + pt.y = shoulder1.y + n*m_branchSpacing; + + stemPt.x = neck.x; + stemPt.y = pt.y; + break; + } + case 3: + { + pt.x = neck.x - m_branchStemLength; + pt.y = shoulder1.y + n*m_branchSpacing; + + stemPt.x = neck.x; + stemPt.y = pt.y; + break; + } + default: + { + wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentPoint." ); + break; + } + } + + return TRUE; +} + +// Get the number of lines at this attachment position. +int wxShape::GetAttachmentLineCount(int attachment) const +{ + int count = 0; + wxNode* node = m_lines.First(); + while (node) + { + wxLineShape* lineShape = (wxLineShape*) node->Data(); + if ((lineShape->GetFrom() == this) && (lineShape->GetAttachmentFrom() == attachment)) + count ++; + else if ((lineShape->GetTo() == this) && (lineShape->GetAttachmentTo() == attachment)) + count ++; + + node = node->Next(); + } + return count; +} + +// This function gets the root point at the given attachment. +wxRealPoint wxShape::GetBranchingAttachmentRoot(int attachment) +{ + int physicalAttachment = LogicalToPhysicalAttachment(attachment); + + wxRealPoint root; + + double width, height; + GetBoundingBoxMax(& width, & height); + + // Assume that we have attachment points 0 to 3: top, right, bottom, left. + switch (physicalAttachment) + { + case 0: + { + root.x = GetX() ; + root.y = GetY() - height/2.0; + break; + } + case 1: + { + root.x = GetX() + width/2.0; + root.y = GetY() ; + break; + } + case 2: + { + root.x = GetX() ; + root.y = GetY() + height/2.0; + break; + } + case 3: + { + root.x = GetX() - width/2.0; + root.y = GetY() ; + break; + } + default: + { + wxFAIL_MSG( "Unrecognised attachment point in GetBranchingAttachmentRoot." ); + break; + } + } + return root; +} + +// Draw or erase the branches (not the actual arcs though) +void wxShape::OnDrawBranches(wxDC& dc, int attachment, bool erase) +{ + int count = GetAttachmentLineCount(attachment); + if (count == 0) + return; + + wxRealPoint root, neck, shoulder1, shoulder2; + GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2); + + if (erase) + { + dc.SetPen(*wxWHITE_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + } + else + { + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxBLACK_BRUSH); + } + + // Draw neck + dc.DrawLine((long) root.x, (long) root.y, (long) neck.x, (long) neck.y); + + if (count > 1) + { + // Draw shoulder-to-shoulder line + dc.DrawLine((long) shoulder1.x, (long) shoulder1.y, (long) shoulder2.x, (long) shoulder2.y); + } + // Draw all the little branches + int i; + for (i = 0; i < count; i++) + { + wxRealPoint pt, stemPt; + GetBranchingAttachmentPoint(attachment, i, pt, stemPt); + dc.DrawLine((long) stemPt.x, (long) stemPt.y, (long) pt.x, (long) pt.y); + + if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB) && (count > 1)) + { + long blobSize=6; +// dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize); + dc.DrawEllipse((long) (stemPt.x - (blobSize/2.0)), (long) (stemPt.y - (blobSize/2.0)), blobSize, blobSize); + } + } +} + +// Draw or erase the branches (not the actual arcs though) +void wxShape::OnDrawBranches(wxDC& dc, bool erase) +{ + if (m_attachmentMode != ATTACHMENT_MODE_BRANCHING) + return; + + int count = GetNumberOfAttachments(); + int i; + for (i = 0; i < count; i++) + OnDrawBranches(dc, i, erase); +} + +// Only get the attachment position at the _edge_ of the shape, ignoring +// branching mode. This is used e.g. to indicate the edge of interest, not the point +// on the attachment branch. +bool wxShape::GetAttachmentPositionEdge(int attachment, double *x, double *y, + int nth, int no_arcs, wxLineShape *line) +{ + int oldMode = m_attachmentMode; + + // Calculate as if to edge, not branch + if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING) + m_attachmentMode = ATTACHMENT_MODE_EDGE; + bool success = GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); + m_attachmentMode = oldMode; + + return success; +} + +// Rotate the standard attachment point from physical (0 is always North) +// to logical (0 -> 1 if rotated by 90 degrees) +int wxShape::PhysicalToLogicalAttachment(int physicalAttachment) const +{ + const double pi = 3.1415926535897932384626433832795 ; + int i; + if (oglRoughlyEqual(GetRotation(), 0.0)) + { + i = physicalAttachment; + } + else if (oglRoughlyEqual(GetRotation(), (pi/2.0))) + { + i = physicalAttachment - 1; + } + else if (oglRoughlyEqual(GetRotation(), pi)) + { + i = physicalAttachment - 2; + } + else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0))) + { + i = physicalAttachment - 3; + } + else + // Can't handle -- assume the same. + return physicalAttachment; + + if (i < 0) + i += 4; + + return i; +} + +// Rotate the standard attachment point from logical +// to physical (0 is always North) +int wxShape::LogicalToPhysicalAttachment(int logicalAttachment) const +{ + const double pi = 3.1415926535897932384626433832795 ; + int i; + if (oglRoughlyEqual(GetRotation(), 0.0)) + { + i = logicalAttachment; + } + else if (oglRoughlyEqual(GetRotation(), (pi/2.0))) + { + i = logicalAttachment + 1; + } + else if (oglRoughlyEqual(GetRotation(), pi)) + { + i = logicalAttachment + 2; + } + else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0))) + { + i = logicalAttachment + 3; + } + else + // Can't handle -- assume the same. + return logicalAttachment; + + if (i > 3) + i -= 4; + + return i; +} + +void wxShape::Rotate(double WXUNUSED(x), double WXUNUSED(y), double theta) +{ + const double pi = 3.1415926535897932384626433832795 ; + m_rotation = theta; + if (m_rotation < 0.0) + { + m_rotation += 2*pi; + } + else if (m_rotation > 2*pi) + { + m_rotation -= 2*pi; + } +} +