pgadmin3/hotdraw/main/hdDrawingView.cpp
2020-07-07 22:19:12 +05:00

473 lines
14 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// hdDrawingView.cpp - Main canvas where all figures are drawn
//
//////////////////////////////////////////////////////////////////////////
#include "pgAdmin3.h"
// wxWindows headers
#include <wx/wx.h>
#include <wx/dcbuffer.h>
// App headers
#include "hotdraw/main/hdDrawingView.h"
#include "hotdraw/utilities/hdArrayCollection.h"
#include "hotdraw/main/hdDrawingEditor.h"
#include "hotdraw/utilities/hdGeometry.h"
#include "hotdraw/utilities/hdMouseEvent.h"
#include "hotdraw/tools/hdCanvasMenuTool.h"
#include "hotdraw/figures/defaultAttributes/hdFontAttribute.h"
#include "hotdraw/tools/hdSelectionTool.h"
// Images
#include "images/check.pngc"
#include "images/ddcancel.pngc"
BEGIN_EVENT_TABLE(hdDrawingView, wxScrolledWindow)
EVT_PAINT( hdDrawingView::onPaint)
EVT_MOTION( hdDrawingView::onMotion)
EVT_RIGHT_DOWN( hdDrawingView::onMouseDown)
EVT_RIGHT_UP( hdDrawingView::onMouseUp)
EVT_LEFT_DOWN( hdDrawingView::onMouseDown)
EVT_LEFT_DCLICK( hdDrawingView::onMouseDown)
EVT_LEFT_UP( hdDrawingView::onMouseUp)
EVT_ERASE_BACKGROUND( hdDrawingView::onEraseBackGround) //This erase flicker
EVT_TEXT(CTL_TEXTTOOLID, hdDrawingView::simpleTextToolChangeHandler)
EVT_BUTTON(CTL_OKBUTTONID, hdDrawingView::OnOkTxtButton)
EVT_BUTTON(CTL_CANCELBUTTONID, hdDrawingView::OnCancelTxtButton)
EVT_KEY_DOWN( hdDrawingView::onKeyDown)
EVT_KEY_UP( hdDrawingView::onKeyUp)
END_EVENT_TABLE()
hdDrawingView::hdDrawingView(int diagram, wxWindow *ddParent, hdDrawingEditor *editor, wxSize size, hdDrawing *initialDrawing)// gqbController *controller, gqbModel *model)
: wxScrolledWindow(ddParent, wxID_ANY, wxPoint(0, 0), size,
wxHSCROLL | wxVSCROLL | wxBORDER | wxRETAINED)
{
diagramIndex = diagram;
drawing = initialDrawing;
drawingEditor = editor;
canvasSize = size;
#if wxCHECK_VERSION(2, 9, 0)
FitInside();
#else
SetVirtualSizeHints(canvasSize);
#endif
// Hack to avoid selection rectangle drawing bug
drawSelRect = false;
// Hack to avoid event problem with simpleTextTool wxTextCrtl at EVT_TEXT event
simpleTextToolEdit = new wxTextCtrl(this, CTL_TEXTTOOLID, wxT(""), wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
simpleTextToolEdit->Hide();
simpleTextFigure = NULL;
menuFigure = NULL;
okTxtButton = new wxBitmapButton(this, CTL_OKBUTTONID, *check_png_bmp, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
okTxtButton->Hide();
cancelTxtButton = new wxBitmapButton(this, 1981, wxBitmap(*ddcancel_png_img), wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
cancelTxtButton->Hide();
canvasMenu = NULL;
_tool = NULL;
_tool = new hdSelectionTool(this);
}
hdDrawingView::~hdDrawingView()
{
if(simpleTextToolEdit)
delete simpleTextToolEdit;
if(okTxtButton)
delete okTxtButton;
if(cancelTxtButton)
delete cancelTxtButton;
if(_tool)
delete _tool;
}
void hdDrawingView::onPaint(wxPaintEvent &event)
{
// Prepare Context for Buffered Draw
wxPaintDC dcc(this);
wxBufferedDC dc(&dcc, canvasSize);
dc.Clear();
hdIFigure *toDraw = NULL;
hdIteratorBase *iterator = drawing->figuresEnumerator();
while(iterator->HasNext())
{
toDraw = (hdIFigure *)iterator->Next();
if(toDraw->isSelected(diagramIndex))
toDraw->drawSelected(dc, this);
else
toDraw->draw(dc, this);
}
delete iterator;
hdIHandle *tmpHandle = NULL;
hdIteratorBase *selectionIterator = drawing->selectionFigures();//selection->createIterator();
while(selectionIterator->HasNext())
{
toDraw = (hdIFigure *)selectionIterator->Next();
hdIteratorBase *handlesIterator = toDraw->handlesEnumerator()->createIterator();
while(handlesIterator->HasNext())
{
tmpHandle = (hdIHandle *)handlesIterator->Next();
tmpHandle->draw(dc, this);
}
delete handlesIterator;
}
delete selectionIterator;
//Hack to avoid selection rectangle drawing bug
if (drawSelRect)
{
wxPen *pen = wxThePenList->FindOrCreatePen(*wxRED, 1, wxDOT);
dc.SetPen(*pen);
wxBrush *brush = wxTheBrushList->FindOrCreateBrush(*wxRED, wxTRANSPARENT);
dc.SetBackground(*brush);
dc.SetBackgroundMode(wxTRANSPARENT);
//Adjust points before drawing
wxPoint selAjustedPoints[5];
CalcScrolledPosition(selPoints[0].x, selPoints[0].y, &selAjustedPoints[0].x, &selAjustedPoints[0].y);
CalcScrolledPosition(selPoints[1].x, selPoints[1].y, &selAjustedPoints[1].x, &selAjustedPoints[1].y);
CalcScrolledPosition(selPoints[2].x, selPoints[2].y, &selAjustedPoints[2].x, &selAjustedPoints[2].y);
CalcScrolledPosition(selPoints[3].x, selPoints[3].y, &selAjustedPoints[3].x, &selAjustedPoints[3].y);
CalcScrolledPosition(selPoints[4].x, selPoints[4].y, &selAjustedPoints[4].x, &selAjustedPoints[4].y);
//Draw
dc.DrawLines(5, selAjustedPoints, 0, 0);
drawSelRect = false;
}
}
//Hack to avoid selection rectangle drawing bug
void hdDrawingView::disableSelRectDraw()
{
drawSelRect = false;
}
//Hack to avoid selection rectangle drawing bug
void hdDrawingView::setSelRect(hdRect &selectionRect)
{
//Create rectangle lines to avoid non transparent brush for filling bug in wxwidgets
selPoints[0].x = selectionRect.x;
selPoints[0].y = selectionRect.y;
selPoints[1].x = selectionRect.x + selectionRect.width;
selPoints[1].y = selectionRect.y;
selPoints[2].x = selectionRect.x + selectionRect.width;
selPoints[2].y = selectionRect.y + selectionRect.height;
selPoints[3].x = selectionRect.x;
selPoints[3].y = selectionRect.y + selectionRect.height;
selPoints[4].x = selectionRect.x;
selPoints[4].y = selectionRect.y;
drawSelRect = true;
}
// Overwrite and disable onEraseBackground Event to avoid Flicker
void hdDrawingView::onEraseBackGround(wxEraseEvent &event)
{
}
hdMultiPosRect hdDrawingView::getVisibleArea()
{
int x, y, w, h;
GetViewStart(&x, &y);
GetClientSize(&w, &h);
hdMultiPosRect visibleArea(x, y, w, h);
return visibleArea;
}
hdMultiPosRect hdDrawingView::getVirtualSize()
{
int w, h;
GetVirtualSize(&w, &h);
hdMultiPosRect virtualSize(0, 0, w, h);
return virtualSize;
}
void hdDrawingView::ScrollToMakeVisible(hdPoint p)
{
//implement this function
}
void hdDrawingView::ScrollToMakeVisible (hdRect r)
{
//implement this function
}
hdIHandle *hdDrawingView::findHandle(int posIdx, double x, double y)
{
hdIFigure *tmpFigure = NULL;
hdIHandle *tmpHandle = NULL, *out = NULL;
//Look for handles at each figure in SelectionEnumerator
hdIteratorBase *selectionIterator = drawing->selectionFigures(); //selection->createIterator();
while(selectionIterator->HasNext())
{
tmpFigure = (hdIFigure *)selectionIterator->Next();
hdIteratorBase *handlesIterator = tmpFigure->handlesEnumerator()->createIterator();
while(handlesIterator->HasNext())
{
tmpHandle = (hdIHandle *)handlesIterator->Next();
if(tmpHandle->containsPoint(posIdx, x, y))
{
out = tmpHandle;
break;
}
}
delete handlesIterator;
}
delete selectionIterator;
return out;
}
hdDrawing *hdDrawingView::getDrawing()
{
return drawing;
}
void hdDrawingView::onMotion(wxMouseEvent &event)
{
// simple hack to don't update so frequently the canvas and mouse events
// Should be changed for a better one using time intervals not a simple counter
static int simpleOptimization = 0;
simpleOptimization++;
if(simpleOptimization > 0)
{
simpleOptimization = 0;
hdMouseEvent ddEvent = hdMouseEvent(event, this);
if(event.Dragging())
{
_tool->mouseDrag(ddEvent);
this->Refresh(); //only a dragging event on montion will change model
}
else
{
_tool->mouseMove(ddEvent);
}
}
}
void hdDrawingView::onMouseDown(wxMouseEvent &event)
{
this->AcceptsFocus();
this->SetFocus();
startDrag = event.GetPosition();
hdMouseEvent ddEvent = hdMouseEvent(event, this);
_tool->mouseDown(ddEvent);
this->Refresh();
}
void hdDrawingView::onMouseUp(wxMouseEvent &event)
{
this->AcceptsFocus();
this->SetFocus();
hdMouseEvent ddEvent = hdMouseEvent(event, this);
_tool->mouseUp(ddEvent);
this->Refresh();
}
void hdDrawingView::onKeyDown(wxKeyEvent &event)
{
hdKeyEvent ddEvent = hdKeyEvent(event, this);
_tool->keyDown(ddEvent);
this->Refresh();
}
void hdDrawingView::onKeyUp(wxKeyEvent &event)
{
hdKeyEvent ddEvent = hdKeyEvent(event, this);
_tool->keyUp(ddEvent);
this->Refresh();
}
//Hack to avoid event problem with simpleTextTool wxTextCrtl at EVT_TEXT event
void hdDrawingView::setSimpleTextToolFigure(hdSimpleTextFigure *figure, bool onlySetFigure)
{
simpleTextFigure = figure;
menuFigure = NULL;
if(simpleTextFigure && !onlySetFigure)
{
oldText = simpleTextFigure->getText();
simpleTextToolEdit->SetValue(simpleTextFigure->getText());
simpleTextToolEdit->SelectAll();
}
}
//Hack to allow use (events) of wxmenu inside a tool Generic Way
void hdDrawingView::setMenuToolFigure(hdAbstractMenuFigure *figure)
{
menuFigure = figure;
simpleTextFigure = NULL;
}
//Hack to avoid event problem with simpleTextTool wxTextCrtl at EVT_TEXT event
void hdDrawingView::OnOkTxtButton(wxCommandEvent &event)
{
_tool->deactivate(this);
simpleTextToolEdit->Hide();
okTxtButton->Hide();
cancelTxtButton->Hide();
setSimpleTextToolFigure(NULL);
}
//Hack to avoid event problem with simpleTextTool wxTextCrtl at EVT_TEXT event
void hdDrawingView::OnCancelTxtButton(wxCommandEvent &event)
{
simpleTextToolEdit->SetValue(oldText);
_tool->deactivate(this);
simpleTextToolEdit->Hide();
okTxtButton->Hide();
cancelTxtButton->Hide();
setSimpleTextToolFigure(NULL);
}
//Hack to avoid event problem with simpleTextTool wxTextCrtl at EVT_TEXT event (when text is set at edit it generate this event not sure ????)
void hdDrawingView::simpleTextToolChangeHandler(wxCommandEvent &event)
{
if(!simpleTextToolEdit->IsModified() && simpleTextFigure)
{
simpleTextFigure->setText(simpleTextToolEdit->GetValue());
//getFontMetrics
int width, height;
wxWindowDC dc(this);
dc.SetFont(*hdFontAttribute::defaultFont);
if(simpleTextFigure->getText(true).length() > 5)
dc.GetTextExtent(simpleTextFigure->getText(true), &width, &height);
else
dc.GetTextExtent(wxT("EMPTY"), &width, &height);
//recalculateDisplayBox
hdGeometry g;
simpleTextFigure->displayBox().width = g.max(width, 10) + simpleTextFigure->getPadding();
simpleTextFigure->displayBox().height = g.max(height, 10) + simpleTextFigure->getPadding();
//calculateSizeEntry
hdPoint p = simpleTextFigure->displayBox().GetPosition(this->diagramIndex);
CalcScrolledPosition(p.x, p.y, &p.x, &p.y);
simpleTextToolEdit->SetPosition(p);
simpleTextToolEdit->SetSize(simpleTextFigure->displayBox().GetSize());
okTxtButton->SetPosition(wxPoint(p.x + simpleTextToolEdit->GetSize().GetWidth() + 4, p.y));
cancelTxtButton->SetPosition(wxPoint(okTxtButton->GetPosition().x + okTxtButton->GetSize().GetWidth() + 4, p.y));
}
else if(!simpleTextFigure)
{
wxMessageDialog *error = new wxMessageDialog(NULL, wxT("Error locating hdSimpleTextTool figure"), wxT("Error!"), wxOK | wxICON_ERROR);
error->ShowModal();
delete error;
}
event.Skip();
}
//Hack to avoid event problem with simpleTextTool wxTextCrtl at EVT_TEXT event
wxTextCtrl *hdDrawingView::getSimpleTextToolEdit()
{
return simpleTextToolEdit;
}
//Hack to avoid event problem with simpleTextTool wxTextCrtl at EVT_TEXT event
wxBitmapButton *hdDrawingView::getOkTxt()
{
return okTxtButton;
}
//Hack to avoid event problem with simpleTextTool wxTextCrtl at EVT_TEXT event
wxBitmapButton *hdDrawingView::getCancelTxt()
{
return cancelTxtButton;
}
//Hack to allow use (events) of wxmenu inside a tool like simpletexttool
void hdDrawingView::OnGenericPopupClick(wxCommandEvent &event)
{
if(canvasMenu)
canvasMenu->OnGenericPopupClick(event, this);
else if(menuFigure)
menuFigure->OnGenericPopupClick(event, this);
else if(simpleTextFigure)
simpleTextFigure->OnGenericPopupClick(event, this);
simpleTextFigure = NULL;
menuFigure = NULL;
canvasMenu = NULL;
event.Skip();
}
//Hack to allow use (events) of wxmenu inside a tool like simpletexttool
void hdDrawingView::connectPopUpMenu(wxMenu &mnu)
{
// Connect the main menu
mnu.Connect(wxEVT_COMMAND_MENU_SELECTED,
(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &hdDrawingView::OnGenericPopupClick,
NULL,
this);
// Connect all submenus
wxMenuItem *item;
wxMenuItemList list = mnu.GetMenuItems();
for (unsigned int index = 0; index < list.GetCount(); index++)
{
wxMenuItemList::compatibility_iterator node = list.Item(index);
item = (wxMenuItem *) node->GetData();
if (item->IsSubMenu())
{
wxMenu *submenu = item->GetSubMenu();
submenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &hdDrawingView::OnGenericPopupClick,
NULL,
this);
}
}
}
//Hack to allow use (events) of wxmenu inside a tool without a figure, Generic Way
void hdDrawingView::setCanvasMenuTool(hdCanvasMenuTool *menuTool)
{
canvasMenu = menuTool;
}
hdDrawingEditor *hdDrawingView::editor()
{
return drawingEditor;
}
bool hdDrawingView::AcceptsFocus() const
{
return true;
}
void hdDrawingView::setTool(hdITool *tool)
{
if(_tool)
delete _tool;
_tool = tool;
}
void hdDrawingView::createViewMenu(wxMenu &mnu)
{
wxMenuItem *item;
item = mnu.AppendCheckItem(1000, _("Sample Item"));
item->Check(true);
}
void hdDrawingView::OnGenericViewPopupClick(wxCommandEvent &event)
{
switch(event.GetId())
{
case 1000:
wxMessageBox(_("Sample menu item"), _("Sample"), wxOK, this);
}
}
void hdDrawingView::notifyChanged()
{
drawingEditor->notifyChanged();
}