1fc25a89ac
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6407 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1040 lines
30 KiB
C++
1040 lines
30 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: view.cpp
|
|
// Purpose: Implements view functionality
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 12/07/98
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) Julian Smart
|
|
// Licence:
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef __GNUG__
|
|
// #pragma implementation
|
|
#endif
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include <wx/wxprec.h>
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include <wx/wx.h>
|
|
#endif
|
|
|
|
#include <wx/colordlg.h>
|
|
|
|
#if !wxUSE_DOC_VIEW_ARCHITECTURE
|
|
#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
|
|
#endif
|
|
|
|
#include "studio.h"
|
|
#include "doc.h"
|
|
#include "view.h"
|
|
#include "cspalette.h"
|
|
#include "symbols.h"
|
|
#include "dialogs.h"
|
|
#include <wx/ogl/basicp.h>
|
|
#include <wx/ogl/linesp.h>
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(csDiagramView, wxView)
|
|
|
|
BEGIN_EVENT_TABLE(csDiagramView, wxView)
|
|
EVT_MENU(wxID_CUT, csDiagramView::OnCut)
|
|
EVT_MENU(wxID_COPY, csDiagramView::OnCopy)
|
|
EVT_MENU(wxID_CLEAR, csDiagramView::OnClear)
|
|
EVT_MENU(wxID_PASTE, csDiagramView::OnPaste)
|
|
EVT_MENU(wxID_DUPLICATE, csDiagramView::OnDuplicate)
|
|
EVT_MENU(ID_CS_CHANGE_BACKGROUND_COLOUR, csDiagramView::OnChangeBackgroundColour)
|
|
EVT_MENU(ID_CS_EDIT_PROPERTIES, csDiagramView::OnEditProperties)
|
|
EVT_MENU(ID_CS_SELECT_ALL, csDiagramView::OnSelectAll)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_LINE_ARROW, csDiagramView::OnToggleArrowTool)
|
|
EVT_COMBOBOX(ID_WINDOW_POINT_SIZE_COMBOBOX, csDiagramView::OnPointSizeComboSel)
|
|
EVT_COMBOBOX(ID_WINDOW_ZOOM_COMBOBOX, csDiagramView::OnZoomSel)
|
|
EVT_TEXT(ID_WINDOW_POINT_SIZE_COMBOBOX, csDiagramView::OnPointSizeComboText)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNL, csDiagramView::OnAlign)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNR, csDiagramView::OnAlign)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNB, csDiagramView::OnAlign)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNT, csDiagramView::OnAlign)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_ALIGN_HORIZ, csDiagramView::OnAlign)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_ALIGN_VERT, csDiagramView::OnAlign)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_COPY_SIZE, csDiagramView::OnAlign)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_NEW_POINT, csDiagramView::OnNewLinePoint)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_CUT_POINT, csDiagramView::OnCutLinePoint)
|
|
EVT_TOOL(DIAGRAM_TOOLBAR_STRAIGHTEN, csDiagramView::OnStraightenLines)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNL, csDiagramView::OnAlignUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNR, csDiagramView::OnAlignUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNB, csDiagramView::OnAlignUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNT, csDiagramView::OnAlignUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGN_HORIZ, csDiagramView::OnAlignUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGN_VERT, csDiagramView::OnAlignUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_COPY_SIZE, csDiagramView::OnAlignUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_NEW_POINT, csDiagramView::OnNewLinePointUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_CUT_POINT, csDiagramView::OnCutLinePointUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_STRAIGHTEN, csDiagramView::OnStraightenLinesUpdate)
|
|
EVT_UPDATE_UI(DIAGRAM_TOOLBAR_LINE_ARROW, csDiagramView::OnToggleArrowToolUpdate)
|
|
EVT_UPDATE_UI(wxID_CUT, csDiagramView::OnCutUpdate)
|
|
EVT_UPDATE_UI(wxID_COPY, csDiagramView::OnCopyUpdate)
|
|
EVT_UPDATE_UI(wxID_CLEAR, csDiagramView::OnClearUpdate)
|
|
EVT_UPDATE_UI(wxID_PASTE, csDiagramView::OnPasteUpdate)
|
|
EVT_UPDATE_UI(wxID_DUPLICATE, csDiagramView::OnDuplicateUpdate)
|
|
EVT_UPDATE_UI(ID_CS_EDIT_PROPERTIES, csDiagramView::OnEditPropertiesUpdate)
|
|
EVT_UPDATE_UI(wxID_UNDO, csDiagramView::OnUndoUpdate)
|
|
EVT_UPDATE_UI(wxID_REDO, csDiagramView::OnRedoUpdate)
|
|
END_EVENT_TABLE()
|
|
|
|
// What to do when a view is created. Creates actual
|
|
// windows for displaying the view.
|
|
bool csDiagramView::OnCreate(wxDocument *doc, long flags)
|
|
{
|
|
wxMenu* editMenu;
|
|
frame = wxGetApp().CreateChildFrame(doc, this, &editMenu);
|
|
canvas = wxGetApp().CreateCanvas(this, frame);
|
|
canvas->SetView(this);
|
|
|
|
SetFrame(frame);
|
|
Activate(TRUE);
|
|
|
|
// Initialize the edit menu Undo and Redo items
|
|
doc->GetCommandProcessor()->SetEditMenu(editMenu);
|
|
doc->GetCommandProcessor()->Initialize();
|
|
|
|
wxShapeCanvas *shapeCanvas = (wxShapeCanvas *)canvas;
|
|
csDiagramDocument *diagramDoc = (csDiagramDocument *)doc;
|
|
shapeCanvas->SetDiagram(diagramDoc->GetDiagram());
|
|
diagramDoc->GetDiagram()->SetCanvas(shapeCanvas);
|
|
|
|
diagramDoc->GetDiagram()->SetGridSpacing((double) wxGetApp().GetGridSpacing());
|
|
|
|
switch (wxGetApp().GetGridStyle())
|
|
{
|
|
case csGRID_STYLE_NONE:
|
|
{
|
|
diagramDoc->GetDiagram()->SetSnapToGrid(FALSE);
|
|
break;
|
|
}
|
|
case csGRID_STYLE_INVISIBLE:
|
|
{
|
|
diagramDoc->GetDiagram()->SetSnapToGrid(TRUE);
|
|
break;
|
|
}
|
|
case csGRID_STYLE_DOTTED:
|
|
{
|
|
// TODO (not implemented in OGL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
csDiagramView::~csDiagramView(void)
|
|
{
|
|
if (frame)
|
|
{
|
|
((wxDocMDIChildFrame*)frame)->SetView(NULL);
|
|
}
|
|
}
|
|
|
|
// Sneakily gets used for default print/preview
|
|
// as well as drawing on the screen.
|
|
void csDiagramView::OnDraw(wxDC *dc)
|
|
{
|
|
}
|
|
|
|
void csDiagramView::OnUpdate(wxView *sender, wxObject *hint)
|
|
{
|
|
if (canvas)
|
|
canvas->Refresh();
|
|
}
|
|
|
|
// Clean up windows used for displaying the view.
|
|
bool csDiagramView::OnClose(bool deleteWindow)
|
|
{
|
|
if (!GetDocument()->Close())
|
|
return FALSE;
|
|
|
|
csDiagramDocument *diagramDoc = (csDiagramDocument *)GetDocument();
|
|
diagramDoc->GetDiagram()->SetCanvas(NULL);
|
|
|
|
canvas->Clear();
|
|
canvas->SetDiagram(NULL);
|
|
canvas->SetView(NULL);
|
|
canvas = NULL;
|
|
|
|
wxMenu* fileMenu = frame->GetMenuBar()->GetMenu(0);
|
|
|
|
// Remove file menu from those managed by the command history
|
|
wxGetApp().GetDocManager()->FileHistoryRemoveMenu(fileMenu);
|
|
|
|
Activate(FALSE);
|
|
frame->Show(FALSE);
|
|
|
|
if (deleteWindow)
|
|
{
|
|
frame->Destroy();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Adds or removes shape from m_selections
|
|
void csDiagramView::SelectShape(wxShape* shape, bool select)
|
|
{
|
|
if (select && !m_selections.Member(shape))
|
|
m_selections.Append(shape);
|
|
else if (!select)
|
|
m_selections.DeleteObject(shape);
|
|
}
|
|
|
|
void csDiagramView::OnSelectAll(wxCommandEvent& event)
|
|
{
|
|
SelectAll(TRUE);
|
|
}
|
|
|
|
wxShape *csDiagramView::FindFirstSelectedShape(void)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
wxShape *theShape = NULL;
|
|
wxNode *node = doc->GetDiagram()->GetShapeList()->First();
|
|
while (node)
|
|
{
|
|
wxShape *eachShape = (wxShape *)node->Data();
|
|
if ((eachShape->GetParent() == NULL) && !eachShape->IsKindOf(CLASSINFO(wxLabelShape)) && eachShape->Selected())
|
|
{
|
|
theShape = eachShape;
|
|
node = NULL;
|
|
}
|
|
else node = node->Next();
|
|
}
|
|
return theShape;
|
|
}
|
|
|
|
void csDiagramView::FindSelectedShapes(wxList& selections, wxClassInfo* toFind)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
wxNode *node = doc->GetDiagram()->GetShapeList()->First();
|
|
while (node)
|
|
{
|
|
wxShape *eachShape = (wxShape *)node->Data();
|
|
if ((eachShape->GetParent() == NULL) && !eachShape->IsKindOf(CLASSINFO(wxLabelShape)) && eachShape->Selected() && ((toFind == NULL) || (eachShape->IsKindOf(toFind))))
|
|
{
|
|
selections.Append(eachShape);
|
|
}
|
|
node = node->Next();
|
|
}
|
|
}
|
|
|
|
void csDiagramView::OnUndoUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
event.Enable(doc->GetCommandProcessor()->CanUndo());
|
|
}
|
|
|
|
void csDiagramView::OnRedoUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
event.Enable(doc->GetCommandProcessor()->CanRedo());
|
|
}
|
|
|
|
void csDiagramView::OnCut(wxCommandEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
// Copy the shapes to the clipboard
|
|
wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram());
|
|
|
|
wxList selections;
|
|
FindSelectedShapes(selections);
|
|
|
|
DoCut(selections);
|
|
}
|
|
|
|
void csDiagramView::OnClear(wxCommandEvent& event)
|
|
{
|
|
wxList selections;
|
|
FindSelectedShapes(selections);
|
|
|
|
DoCut(selections);
|
|
}
|
|
|
|
void csDiagramView::OnCopy(wxCommandEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
// Copy the shapes to the clipboard
|
|
if (wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram()))
|
|
{
|
|
#ifdef __WXMSW__
|
|
// Copy to the Windows clipboard
|
|
wxGetApp().GetDiagramClipboard().CopyToClipboard(1.0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void csDiagramView::OnPaste(wxCommandEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
wxGetApp().GetDiagramClipboard().Paste(doc->GetDiagram());
|
|
}
|
|
|
|
void csDiagramView::OnDuplicate(wxCommandEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
// Do a copy, then a paste
|
|
wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram());
|
|
|
|
// Apply an offset. Really, this offset should keep being incremented,
|
|
// but where do we reset it again?
|
|
wxGetApp().GetDiagramClipboard().Paste(doc->GetDiagram(), NULL, 20, 20);
|
|
}
|
|
|
|
void csDiagramView::OnCutUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable( (m_selections.Number() > 0) );
|
|
}
|
|
|
|
void csDiagramView::OnClearUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable( (m_selections.Number() > 0) );
|
|
}
|
|
|
|
void csDiagramView::OnCopyUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable( (m_selections.Number() > 0) );
|
|
}
|
|
|
|
void csDiagramView::OnPasteUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
int n = wxGetApp().GetDiagramClipboard().GetCount();
|
|
|
|
event.Enable( (n > 0) );
|
|
}
|
|
|
|
void csDiagramView::OnDuplicateUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
event.Enable( (m_selections.Number() > 0) );
|
|
}
|
|
|
|
void csDiagramView::DoCut(wxList& shapes)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
if (shapes.Number() > 0)
|
|
{
|
|
csDiagramCommand* cmd = new csDiagramCommand("Cut", doc);
|
|
|
|
wxNode* node = shapes.First();
|
|
while (node)
|
|
{
|
|
wxShape *theShape = (wxShape*) node->Data();
|
|
csCommandState* state = new csCommandState(ID_CS_CUT, NULL, theShape);
|
|
|
|
// Insert lines at the front, so they are cut first.
|
|
// Otherwise we may try to remove a shape with a line still
|
|
// attached.
|
|
if (theShape->IsKindOf(CLASSINFO(wxLineShape)))
|
|
cmd->InsertState(state);
|
|
else
|
|
cmd->AddState(state);
|
|
|
|
node = node->Next();
|
|
}
|
|
cmd->RemoveLines(); // Schedule any connected lines, not already mentioned,
|
|
// to be removed first
|
|
|
|
doc->GetCommandProcessor()->Submit(cmd);
|
|
}
|
|
}
|
|
|
|
// Generalised command
|
|
void csDiagramView::DoCmd(wxList& shapes, wxList& oldShapes, int cmd, const wxString& op)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
if (shapes.Number() > 0)
|
|
{
|
|
csDiagramCommand* command = new csDiagramCommand(op, doc);
|
|
|
|
wxNode* node = shapes.First();
|
|
wxNode* node1 = oldShapes.First();
|
|
while (node && node1)
|
|
{
|
|
wxShape *theShape = (wxShape*) node->Data();
|
|
wxShape *oldShape = (wxShape*) node1->Data();
|
|
csCommandState* state = new csCommandState(cmd, theShape, oldShape);
|
|
command->AddState(state);
|
|
|
|
node = node->Next();
|
|
node1 = node1->Next();
|
|
}
|
|
doc->GetCommandProcessor()->Submit(command);
|
|
}
|
|
}
|
|
|
|
void csDiagramView::OnChangeBackgroundColour(wxCommandEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
wxList selections;
|
|
FindSelectedShapes(selections);
|
|
|
|
if (selections.Number() > 0)
|
|
{
|
|
wxColourData data;
|
|
data.SetChooseFull(TRUE);
|
|
if (selections.Number() == 1)
|
|
{
|
|
wxShape* firstShape = (wxShape*) selections.First()->Data();
|
|
data.SetColour(firstShape->GetBrush()->GetColour());
|
|
}
|
|
|
|
wxColourDialog *dialog = new wxColourDialog(frame, &data);
|
|
wxBrush *theBrush = NULL;
|
|
if (dialog->ShowModal() == wxID_OK)
|
|
{
|
|
wxColourData retData = dialog->GetColourData();
|
|
wxColour col = retData.GetColour();
|
|
theBrush = wxTheBrushList->FindOrCreateBrush(col, wxSOLID);
|
|
}
|
|
dialog->Close(TRUE);
|
|
if (!theBrush)
|
|
return;
|
|
|
|
csDiagramCommand* cmd = new csDiagramCommand("Change colour", doc);
|
|
|
|
wxNode* node = selections.First();
|
|
while (node)
|
|
{
|
|
wxShape *theShape = (wxShape*) node->Data();
|
|
wxShape* newShape = theShape->CreateNewCopy();
|
|
newShape->SetBrush(theBrush);
|
|
|
|
csCommandState* state = new csCommandState(ID_CS_CHANGE_BACKGROUND_COLOUR, newShape, theShape);
|
|
cmd->AddState(state);
|
|
|
|
node = node->Next();
|
|
}
|
|
doc->GetCommandProcessor()->Submit(cmd);
|
|
}
|
|
}
|
|
|
|
void csDiagramView::OnEditProperties(wxCommandEvent& event)
|
|
{
|
|
wxShape *theShape = FindFirstSelectedShape();
|
|
if (theShape)
|
|
((csEvtHandler *)theShape->GetEventHandler())->EditProperties();
|
|
}
|
|
|
|
void csDiagramView::OnEditPropertiesUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
wxList selections;
|
|
FindSelectedShapes(selections);
|
|
event.Enable( (selections.Number() > 0) );
|
|
}
|
|
|
|
void csDiagramView::OnPointSizeComboSel(wxCommandEvent& event)
|
|
{
|
|
wxComboBox* combo = (wxComboBox*) event.GetEventObject();
|
|
wxASSERT( combo != NULL );
|
|
|
|
int newPointSize = (combo->GetSelection() + 1);
|
|
|
|
ApplyPointSize(newPointSize);
|
|
|
|
}
|
|
|
|
// TODO: must find out how to intercept the Return key, rather than
|
|
// every key stroke. But for now, do every key stroke.
|
|
void csDiagramView::OnPointSizeComboText(wxCommandEvent& event)
|
|
{
|
|
wxComboBox* combo = (wxComboBox*) event.GetEventObject();
|
|
wxASSERT( combo != NULL );
|
|
|
|
wxString str(combo->GetValue());
|
|
int newPointSize = atoi((const char*) str);
|
|
|
|
if (newPointSize < 2)
|
|
return;
|
|
|
|
ApplyPointSize(newPointSize);
|
|
}
|
|
|
|
void csDiagramView::ApplyPointSize(int pointSize)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
wxList selections;
|
|
FindSelectedShapes(selections);
|
|
|
|
if (selections.Number() > 0)
|
|
{
|
|
csDiagramCommand* cmd = new csDiagramCommand("Point size", doc);
|
|
|
|
wxNode* node = selections.First();
|
|
while (node)
|
|
{
|
|
wxShape *theShape = (wxShape*) node->Data();
|
|
wxShape *newShape = theShape->CreateNewCopy();
|
|
|
|
wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
|
|
theShape->GetFont()->GetFamily(),
|
|
theShape->GetFont()->GetStyle(),
|
|
theShape->GetFont()->GetWeight(),
|
|
theShape->GetFont()->GetUnderlined(),
|
|
theShape->GetFont()->GetFaceName());
|
|
|
|
newShape->SetFont(newFont);
|
|
|
|
csCommandState* state = new csCommandState(ID_CS_FONT_CHANGE, newShape, theShape);
|
|
|
|
cmd->AddState(state);
|
|
|
|
node = node->Next();
|
|
}
|
|
doc->GetCommandProcessor()->Submit(cmd);
|
|
}
|
|
}
|
|
|
|
void csDiagramView::OnZoomSel(wxCommandEvent& event)
|
|
{
|
|
int maxZoom = 200;
|
|
int minZoom = 5;
|
|
int inc = 5;
|
|
int noStrings = (maxZoom - minZoom)/inc ;
|
|
|
|
wxComboBox* combo = (wxComboBox*) event.GetEventObject();
|
|
wxASSERT( combo != NULL );
|
|
|
|
int scale = (int) ((noStrings - combo->GetSelection() - 1)*inc + minZoom);
|
|
|
|
canvas->SetScale((double) (scale/100.0), (double) (scale/100.0));
|
|
canvas->Refresh();
|
|
}
|
|
|
|
// Select or deselect all
|
|
void csDiagramView::SelectAll(bool select)
|
|
{
|
|
wxClientDC dc(canvas);
|
|
canvas->PrepareDC(dc);
|
|
|
|
if (!select)
|
|
{
|
|
wxList selections;
|
|
FindSelectedShapes(selections);
|
|
|
|
wxNode* node = selections.First();
|
|
while (node)
|
|
{
|
|
wxShape *theShape = (wxShape*) node->Data();
|
|
theShape->Select(FALSE, &dc);
|
|
SelectShape(theShape, FALSE);
|
|
|
|
node = node->Next();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
wxNode *node = doc->GetDiagram()->GetShapeList()->First();
|
|
while (node)
|
|
{
|
|
wxShape *eachShape = (wxShape *)node->Data();
|
|
if (eachShape->GetParent() == NULL &&
|
|
!eachShape->IsKindOf(CLASSINFO(wxControlPoint)) &&
|
|
!eachShape->IsKindOf(CLASSINFO(wxLabelShape)))
|
|
{
|
|
eachShape->Select(TRUE, &dc);
|
|
SelectShape(eachShape, TRUE);
|
|
}
|
|
node = node->Next();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void csDiagramView::OnToggleArrowTool(wxCommandEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
|
|
bool state = wxGetApp().GetDiagramToolBar()->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW);
|
|
wxString stateName;
|
|
if (state)
|
|
stateName = "Arrow on";
|
|
else
|
|
stateName = "Arrow off";
|
|
|
|
wxList selections;
|
|
FindSelectedShapes(selections, CLASSINFO(wxLineShape));
|
|
|
|
if (selections.Number() > 0)
|
|
{
|
|
csDiagramCommand* cmd = new csDiagramCommand(stateName, doc);
|
|
|
|
wxNode* node = selections.First();
|
|
while (node)
|
|
{
|
|
wxLineShape *theShape = (wxLineShape*) node->Data();
|
|
wxLineShape *newShape = NULL;
|
|
|
|
if (state)
|
|
{
|
|
// Add arrow
|
|
if (theShape->GetArrows().Number() == 0)
|
|
{
|
|
newShape = (wxLineShape*) theShape->CreateNewCopy();
|
|
newShape->AddArrow(ARROW_ARROW, ARROW_POSITION_MIDDLE, 10.0, 0.0, "Normal arrowhead");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (theShape->GetArrows().Number() > 0)
|
|
{
|
|
newShape = (wxLineShape*) theShape->CreateNewCopy();
|
|
newShape->ClearArrowsAtPosition();
|
|
}
|
|
}
|
|
|
|
// If the new state is the same as the old, don't bother adding it to the command state.
|
|
if (newShape)
|
|
{
|
|
csCommandState* state = new csCommandState(ID_CS_ARROW_CHANGE, newShape, theShape);
|
|
cmd->AddState(state);
|
|
}
|
|
|
|
node = node->Next();
|
|
}
|
|
doc->GetCommandProcessor()->Submit(cmd);
|
|
}
|
|
}
|
|
|
|
void csDiagramView::OnToggleArrowToolUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
wxList selections;
|
|
FindSelectedShapes(selections, CLASSINFO(wxLineShape));
|
|
event.Enable( (selections.Number() > 0) );
|
|
}
|
|
|
|
// Make the point size combobox reflect this
|
|
void csDiagramView::ReflectPointSize(int pointSize)
|
|
{
|
|
wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
|
|
comboBox->SetSelection(pointSize -1);
|
|
}
|
|
|
|
// Make the arrow toggle button reflect the state of the line
|
|
void csDiagramView::ReflectArrowState(wxLineShape* lineShape)
|
|
{
|
|
bool haveArrow = FALSE;
|
|
wxNode *node = lineShape->GetArrows().First();
|
|
while (node)
|
|
{
|
|
wxArrowHead *arrow = (wxArrowHead *)node->Data();
|
|
if (ARROW_POSITION_MIDDLE == arrow->GetArrowEnd())
|
|
haveArrow = TRUE;
|
|
node = node->Next();
|
|
}
|
|
|
|
wxGetApp().GetDiagramToolBar()->ToggleTool(DIAGRAM_TOOLBAR_LINE_ARROW, haveArrow);
|
|
}
|
|
|
|
void csDiagramView::OnAlign(wxCommandEvent& event)
|
|
{
|
|
// Make a copy of the selections, keeping only those shapes
|
|
// that are top-level non-line shapes.
|
|
wxList selections;
|
|
wxNode* node = GetSelectionList().First();
|
|
while (node)
|
|
{
|
|
wxShape* shape = (wxShape*) node->Data();
|
|
if ((shape->GetParent() == NULL) && (!shape->IsKindOf(CLASSINFO(wxLineShape))))
|
|
{
|
|
selections.Append(shape);
|
|
}
|
|
node = node->Next();
|
|
}
|
|
|
|
if (selections.Number() == 0)
|
|
return;
|
|
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
csDiagramCommand* cmd = new csDiagramCommand("Align", doc);
|
|
|
|
node = selections.First();
|
|
wxShape* firstShape = (wxShape*) node->Data();
|
|
|
|
double x = firstShape->GetX();
|
|
double y = firstShape->GetY();
|
|
double width, height;
|
|
firstShape->GetBoundingBoxMax(&width, &height);
|
|
|
|
node = selections.First();
|
|
while (node)
|
|
{
|
|
wxShape* shape = (wxShape*) node->Data();
|
|
if (shape != firstShape)
|
|
{
|
|
double x1 = shape->GetX();
|
|
double y1 = shape->GetY();
|
|
double width1, height1;
|
|
shape->GetBoundingBoxMax(& width1, & height1);
|
|
|
|
wxShape* newShape = shape->CreateNewCopy();
|
|
|
|
switch (event.GetId())
|
|
{
|
|
case DIAGRAM_TOOLBAR_ALIGNL:
|
|
{
|
|
double x2 = (double)(x - (width/2.0) + (width1/2.0));
|
|
newShape->SetX(x2);
|
|
break;
|
|
}
|
|
case DIAGRAM_TOOLBAR_ALIGNR:
|
|
{
|
|
double x2 = (double)(x + (width/2.0) - (width1/2.0));
|
|
newShape->SetX(x2);
|
|
break;
|
|
}
|
|
case DIAGRAM_TOOLBAR_ALIGNB:
|
|
{
|
|
double y2 = (double)(y + (height/2.0) - (height1/2.0));
|
|
newShape->SetY(y2);
|
|
break;
|
|
}
|
|
case DIAGRAM_TOOLBAR_ALIGNT:
|
|
{
|
|
double y2 = (double)(y - (height/2.0) + (height1/2.0));
|
|
newShape->SetY(y2);
|
|
break;
|
|
}
|
|
case DIAGRAM_TOOLBAR_ALIGN_HORIZ:
|
|
{
|
|
newShape->SetX(x);
|
|
break;
|
|
}
|
|
case DIAGRAM_TOOLBAR_ALIGN_VERT:
|
|
{
|
|
newShape->SetY(y);
|
|
break;
|
|
}
|
|
case DIAGRAM_TOOLBAR_COPY_SIZE:
|
|
{
|
|
newShape->SetSize(width, height);
|
|
break;
|
|
}
|
|
}
|
|
csCommandState* state = new csCommandState(ID_CS_ALIGN, newShape, shape);
|
|
cmd->AddState(state);
|
|
}
|
|
node = node->Next();
|
|
}
|
|
doc->GetCommandProcessor()->Submit(cmd);
|
|
}
|
|
|
|
void csDiagramView::OnAlignUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
// This is an approximation, since there may be lines
|
|
// amongst the selections.
|
|
event.Enable( (m_selections.Number() > 1) ) ;
|
|
}
|
|
|
|
void csDiagramView::OnNewLinePoint(wxCommandEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
csDiagramCommand* cmd = new csDiagramCommand("New line point", doc);
|
|
|
|
wxNode* node = m_selections.First();
|
|
while (node)
|
|
{
|
|
wxShape* shape = (wxShape*) node->Data();
|
|
if (shape->IsKindOf(CLASSINFO(wxLineShape)))
|
|
{
|
|
wxShape* newShape = shape->CreateNewCopy();
|
|
((wxLineShape*)newShape)->InsertLineControlPoint(NULL);
|
|
csCommandState* state = new csCommandState(ID_CS_NEW_POINT, newShape, shape);
|
|
cmd->AddState(state);
|
|
}
|
|
node = node->Next();
|
|
}
|
|
doc->GetCommandProcessor()->Submit(cmd);
|
|
}
|
|
|
|
void csDiagramView::OnCutLinePoint(wxCommandEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
csDiagramCommand* cmd = new csDiagramCommand("Cut line point", doc);
|
|
|
|
wxNode* node = m_selections.First();
|
|
while (node)
|
|
{
|
|
wxShape* shape = (wxShape*) node->Data();
|
|
if (shape->IsKindOf(CLASSINFO(wxLineShape)))
|
|
{
|
|
wxShape* newShape = shape->CreateNewCopy();
|
|
((wxLineShape*)newShape)->DeleteLineControlPoint();
|
|
csCommandState* state = new csCommandState(ID_CS_CUT_POINT, newShape, shape);
|
|
cmd->AddState(state);
|
|
}
|
|
node = node->Next();
|
|
}
|
|
doc->GetCommandProcessor()->Submit(cmd);
|
|
}
|
|
|
|
void csDiagramView::OnStraightenLines(wxCommandEvent& event)
|
|
{
|
|
csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
|
|
csDiagramCommand* cmd = new csDiagramCommand("Straighten lines", doc);
|
|
|
|
wxNode* node = m_selections.First();
|
|
while (node)
|
|
{
|
|
wxShape* shape = (wxShape*) node->Data();
|
|
if (shape->IsKindOf(CLASSINFO(wxLineShape)))
|
|
{
|
|
wxShape* newShape = shape->CreateNewCopy();
|
|
((wxLineShape*)newShape)->Straighten();
|
|
csCommandState* state = new csCommandState(ID_CS_STRAIGHTEN, newShape, shape);
|
|
cmd->AddState(state);
|
|
}
|
|
node = node->Next();
|
|
}
|
|
doc->GetCommandProcessor()->Submit(cmd);
|
|
}
|
|
|
|
void csDiagramView::OnNewLinePointUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
wxList selections;
|
|
FindSelectedShapes(selections, CLASSINFO(wxLineShape));
|
|
event.Enable( (selections.Number() > 0) );
|
|
}
|
|
|
|
void csDiagramView::OnCutLinePointUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
wxList selections;
|
|
FindSelectedShapes(selections, CLASSINFO(wxLineShape));
|
|
event.Enable( (selections.Number() > 0) );
|
|
}
|
|
|
|
void csDiagramView::OnStraightenLinesUpdate(wxUpdateUIEvent& event)
|
|
{
|
|
wxList selections;
|
|
FindSelectedShapes(selections, CLASSINFO(wxLineShape));
|
|
event.Enable( (selections.Number() > 0) );
|
|
}
|
|
|
|
/*
|
|
* Window implementations
|
|
*/
|
|
|
|
IMPLEMENT_CLASS(csCanvas, wxShapeCanvas)
|
|
|
|
BEGIN_EVENT_TABLE(csCanvas, wxShapeCanvas)
|
|
EVT_MOUSE_EVENTS(csCanvas::OnMouseEvent)
|
|
EVT_PAINT(csCanvas::OnPaint)
|
|
END_EVENT_TABLE()
|
|
|
|
// Define a constructor for my canvas
|
|
csCanvas::csCanvas(csDiagramView *v, wxWindow *parent, wxWindowID id, const wxPoint& pos,
|
|
const wxSize& size, long style):
|
|
wxShapeCanvas(parent, id, pos, size, style)
|
|
{
|
|
m_view = v;
|
|
}
|
|
|
|
csCanvas::~csCanvas(void)
|
|
{
|
|
}
|
|
|
|
void csCanvas::DrawOutline(wxDC& dc, double x1, double y1, double x2, double y2)
|
|
{
|
|
wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
|
|
dc.SetPen(dottedPen);
|
|
dc.SetBrush(* wxTRANSPARENT_BRUSH);
|
|
|
|
dc.DrawRectangle((long) x1, (long) y1, (long) (x2 - x1), (long) (y2 - y1));
|
|
}
|
|
|
|
void csCanvas::OnLeftClick(double x, double y, int keys)
|
|
{
|
|
csEditorToolPalette *palette = wxGetApp().GetDiagramPalette();
|
|
|
|
if (palette->GetSelection() == PALETTE_ARROW)
|
|
{
|
|
GetView()->SelectAll(FALSE);
|
|
|
|
wxClientDC dc(this);
|
|
PrepareDC(dc);
|
|
|
|
Redraw(dc);
|
|
return;
|
|
}
|
|
|
|
if (palette->GetSelection() == PALETTE_TEXT_TOOL)
|
|
{
|
|
// Ask for a label and create a new free-floating text region
|
|
csLabelEditingDialog* dialog = new csLabelEditingDialog(GetParent());
|
|
|
|
dialog->SetShapeLabel("");
|
|
dialog->SetTitle("New text box");
|
|
if (dialog->ShowModal() == wxID_CANCEL)
|
|
{
|
|
dialog->Destroy();
|
|
return;
|
|
}
|
|
|
|
wxString newLabel = dialog->GetShapeLabel();
|
|
dialog->Destroy();
|
|
|
|
wxShape* shape = new csTextBoxShape;
|
|
shape->AssignNewIds();
|
|
shape->SetEventHandler(new csEvtHandler(shape, shape, newLabel));
|
|
|
|
wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
|
|
wxString str(comboBox->GetValue());
|
|
int pointSize = atoi((const char*) str);
|
|
|
|
wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
|
|
shape->GetFont()->GetFamily(),
|
|
shape->GetFont()->GetStyle(),
|
|
shape->GetFont()->GetWeight(),
|
|
shape->GetFont()->GetUnderlined(),
|
|
shape->GetFont()->GetFaceName());
|
|
|
|
shape->SetFont(newFont);
|
|
|
|
shape->SetX(x);
|
|
shape->SetY(y);
|
|
|
|
csDiagramCommand* cmd = new csDiagramCommand("Text box",
|
|
(csDiagramDocument *)GetView()->GetDocument(),
|
|
new csCommandState(ID_CS_ADD_SHAPE, shape, NULL));
|
|
GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
|
|
|
|
palette->SetSelection(PALETTE_ARROW);
|
|
|
|
return;
|
|
}
|
|
|
|
csSymbol* symbol = wxGetApp().GetSymbolDatabase()->FindSymbol(palette->GetSelection());
|
|
if (symbol)
|
|
{
|
|
wxShape* theShape = symbol->GetShape()->CreateNewCopy();
|
|
|
|
wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
|
|
wxString str(comboBox->GetValue());
|
|
int pointSize = atoi((const char*) str);
|
|
|
|
wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
|
|
symbol->GetShape()->GetFont()->GetFamily(),
|
|
symbol->GetShape()->GetFont()->GetStyle(),
|
|
symbol->GetShape()->GetFont()->GetWeight(),
|
|
symbol->GetShape()->GetFont()->GetUnderlined(),
|
|
symbol->GetShape()->GetFont()->GetFaceName());
|
|
|
|
theShape->SetFont(newFont);
|
|
|
|
theShape->AssignNewIds();
|
|
theShape->SetX(x);
|
|
theShape->SetY(y);
|
|
|
|
csDiagramCommand* cmd = new csDiagramCommand(symbol->GetName(),
|
|
(csDiagramDocument *)GetView()->GetDocument(),
|
|
new csCommandState(ID_CS_ADD_SHAPE, theShape, NULL));
|
|
GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
|
|
|
|
palette->SetSelection(PALETTE_ARROW);
|
|
}
|
|
}
|
|
|
|
void csCanvas::OnRightClick(double x, double y, int keys)
|
|
{
|
|
}
|
|
|
|
// Initial point
|
|
static double sg_initialX, sg_initialY;
|
|
|
|
void csCanvas::OnDragLeft(bool draw, double x, double y, int keys)
|
|
{
|
|
wxClientDC dc(this);
|
|
PrepareDC(dc);
|
|
|
|
dc.SetLogicalFunction(OGLRBLF);
|
|
DrawOutline(dc, sg_initialX, sg_initialY, x, y);
|
|
}
|
|
|
|
void csCanvas::OnBeginDragLeft(double x, double y, int keys)
|
|
{
|
|
sg_initialX = x;
|
|
sg_initialY = y;
|
|
|
|
wxClientDC dc(this);
|
|
PrepareDC(dc);
|
|
|
|
dc.SetLogicalFunction(OGLRBLF);
|
|
DrawOutline(dc, sg_initialX, sg_initialY, x, y);
|
|
CaptureMouse();
|
|
}
|
|
|
|
void csCanvas::OnEndDragLeft(double x, double y, int keys)
|
|
{
|
|
ReleaseMouse();
|
|
|
|
wxClientDC dc(this);
|
|
PrepareDC(dc);
|
|
|
|
// Select all images within the rectangle
|
|
float min_x, max_x, min_y, max_y;
|
|
min_x = wxMin(x, sg_initialX);
|
|
max_x = wxMax(x, sg_initialX);
|
|
min_y = wxMin(y, sg_initialY);
|
|
max_y = wxMax(y, sg_initialY);
|
|
|
|
wxNode *node = GetDiagram()->GetShapeList()->First();
|
|
while (node)
|
|
{
|
|
wxShape *shape = (wxShape *)node->Data();
|
|
if (shape->GetParent() == NULL && !shape->IsKindOf(CLASSINFO(wxControlPoint)))
|
|
{
|
|
float image_x = shape->GetX();
|
|
float image_y = shape->GetY();
|
|
if (image_x >= min_x && image_x <= max_x &&
|
|
image_y >= min_y && image_y <= max_y)
|
|
{
|
|
shape->Select(TRUE, &dc);
|
|
GetView()->SelectShape(shape, TRUE);
|
|
}
|
|
}
|
|
node = node->Next();
|
|
}
|
|
}
|
|
|
|
void csCanvas::OnDragRight(bool draw, double x, double y, int keys)
|
|
{
|
|
}
|
|
|
|
void csCanvas::OnBeginDragRight(double x, double y, int keys)
|
|
{
|
|
}
|
|
|
|
void csCanvas::OnEndDragRight(double x, double y, int keys)
|
|
{
|
|
}
|
|
|
|
void csCanvas::OnMouseEvent(wxMouseEvent& event)
|
|
{
|
|
wxShapeCanvas::OnMouseEvent(event);
|
|
}
|
|
|
|
void csCanvas::OnPaint(wxPaintEvent& event)
|
|
{
|
|
// if (GetDiagram())
|
|
wxShapeCanvas::OnPaint(event);
|
|
}
|