X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2049ba38adafa0ec146880de29f26e32dd69a125..a7ebaf0ddd8556929c923329e4d61cb0b6520109:/samples/docview/view.cpp?ds=sidebyside diff --git a/samples/docview/view.cpp b/samples/docview/view.cpp index 15784e23f6..d454e56554 100644 --- a/samples/docview/view.cpp +++ b/samples/docview/view.cpp @@ -1,284 +1,368 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: view.cpp -// Purpose: View classes +// Name: samples/docview/view.cpp +// Purpose: View classes implementation // Author: Julian Smart -// Modified by: +// Modified by: Vadim Zeitlin: merge with the MDI version and general cleanup // Created: 04/01/98 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// Copyright: (c) 1998 Julian Smart +// (c) 2008 Vadim Zeitlin +// Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -// #pragma implementation -#endif - // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #ifndef WX_PRECOMP -#include "wx/wx.h" + #include "wx/wx.h" #endif -#if !USE_DOC_VIEW_ARCHITECTURE -#error You must set USE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h! +#if !wxUSE_DOC_VIEW_ARCHITECTURE + #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h! #endif #include "docview.h" #include "doc.h" #include "view.h" -IMPLEMENT_DYNAMIC_CLASS(DrawingView, wxView) +// ---------------------------------------------------------------------------- +// DrawingView implementation +// ---------------------------------------------------------------------------- -// For drawing lines in a canvas -float xpos = -1; -float ypos = -1; +IMPLEMENT_DYNAMIC_CLASS(DrawingView, wxView) BEGIN_EVENT_TABLE(DrawingView, wxView) - EVT_MENU(DOODLE_CUT, DrawingView::OnCut) + EVT_MENU(wxID_CUT, DrawingView::OnCut) END_EVENT_TABLE() // What to do when a view is created. Creates actual // windows for displaying the view. -bool DrawingView::OnCreate(wxDocument *doc, long flags) +bool DrawingView::OnCreate(wxDocument *doc, long WXUNUSED(flags) ) { - if (!singleWindowMode) - { - // Multiple windows - frame = wxGetApp().CreateChildFrame(doc, this, TRUE); - frame->SetTitle("DrawingView"); - - canvas = GetMainFrame()->CreateCanvas(this, frame); -#ifdef __X__ - // X seems to require a forced resize - int x, y; - frame->GetSize(&x, &y); - frame->SetSize(x, y); -#endif - frame->Show(TRUE); - } - else - { - // Single-window mode - frame = GetMainFrame(); - canvas = GetMainFrame()->canvas; - canvas->view = this; - - // Associate the appropriate frame with this view. - SetFrame(frame); - - // Make sure the document manager knows that this is the - // current view. - Activate(TRUE); - - // Initialize the edit menu Undo and Redo items - doc->GetCommandProcessor()->SetEditMenu(((MyFrame *)frame)->editMenu); - doc->GetCommandProcessor()->Initialize(); - } - - return TRUE; + MyApp& app = wxGetApp(); + if ( app.GetMode() != MyApp::Mode_Single ) + { + // create a new window and canvas inside it + m_frame = app.CreateChildFrame(doc, this, true); + m_frame->SetTitle("Drawing View"); + + m_canvas = new MyCanvas(this, m_frame); + m_frame->Show(true); + } + else // single document mode + { + // reuse the existing window and canvas + m_frame = wxStaticCast(app.GetTopWindow(), wxFrame); + m_canvas = app.GetMainWindowCanvas(); + m_canvas->SetView(this); + + // Associate the appropriate frame with this view. + SetFrame(m_frame); + + // Make sure the document manager knows that this is the + // current view. + Activate(true); + + // Initialize the edit menu Undo and Redo items + doc->GetCommandProcessor()->SetEditMenu(app.GetMainWindowEditMenu()); + doc->GetCommandProcessor()->Initialize(); + } + + return true; } -// Sneakily gets used for default print/preview -// as well as drawing on the screen. +// Sneakily gets used for default print/preview as well as drawing on the +// screen. void DrawingView::OnDraw(wxDC *dc) { - dc->SetFont(*wxNORMAL_FONT); - dc->SetPen(*wxBLACK_PEN); - - wxNode *node = ((DrawingDocument *)GetDocument())->GetDoodleSegments().First(); - while (node) - { - DoodleSegment *seg = (DoodleSegment *)node->Data(); - seg->Draw(dc); - node = node->Next(); - } -} + dc->SetPen(*wxBLACK_PEN); -void DrawingView::OnUpdate(wxView *sender, wxObject *hint) -{ - if (canvas) - canvas->Refresh(); - -/* Is the following necessary? -#ifdef __WXMSW__ - if (canvas) - canvas->Refresh(); -#else - if (canvas) + // simply draw all lines of all segments + const DoodleSegments& segments = GetDocument()->GetSegments(); + for ( DoodleSegments::const_iterator i = segments.begin(); + i != segments.end(); + ++i ) { - wxClientDC dc(canvas); - dc.Clear(); - OnDraw(& dc); + const DoodleLines& lines = i->GetLines(); + for ( DoodleLines::const_iterator j = lines.begin(); + j != lines.end(); + ++j ) + { + const DoodleLine& line = *j; + + dc->DrawLine(line.x1, line.y1, line.x2, line.y2); + } } -#endif -*/ +} + +DrawingDocument* DrawingView::GetDocument() +{ + return wxStaticCast(wxView::GetDocument(), DrawingDocument); +} + +void DrawingView::OnUpdate(wxView* sender, wxObject* hint) +{ + wxView::OnUpdate(sender, hint); + if ( m_canvas ) + m_canvas->Refresh(); } // Clean up windows used for displaying the view. bool DrawingView::OnClose(bool deleteWindow) { - if (!GetDocument()->Close()) - return FALSE; - - // Clear the canvas in case we're in single-window mode, - // and the canvas stays. - canvas->Clear(); - canvas->view = NULL; - canvas = NULL; - - wxString s(wxTheApp->GetAppName()); - if (frame) - frame->SetTitle(s); - - SetFrame(NULL); - - Activate(FALSE); - - if (deleteWindow && !singleWindowMode) - { - delete frame; - return TRUE; - } - return TRUE; + if ( !GetDocument()->Close() ) + return false; + + Activate(false); + + // Clear the canvas in single-window mode in which it stays alive + if ( wxGetApp().GetMode() == MyApp::Mode_Single ) + { + m_canvas->ClearBackground(); + m_canvas->ResetView(); + m_canvas = NULL; + + if ( m_frame ) + m_frame->SetTitle(wxTheApp->GetAppDisplayName()); + } + else // not single window mode + { + if ( deleteWindow ) + wxDELETE(m_frame); + } + + SetFrame(NULL); + + return true; } -void DrawingView::OnCut(wxCommandEvent& event) +void DrawingView::OnCut(wxCommandEvent& WXUNUSED(event) ) { - DrawingDocument *doc = (DrawingDocument *)GetDocument(); - doc->GetCommandProcessor()->Submit(new DrawingCommand("Cut Last Segment", DOODLE_CUT, doc, NULL)); + DrawingDocument * const doc = GetDocument(); + + doc->GetCommandProcessor()->Submit(new DrawingRemoveSegmentCommand(doc)); } +// ---------------------------------------------------------------------------- +// TextEditView implementation +// ---------------------------------------------------------------------------- + IMPLEMENT_DYNAMIC_CLASS(TextEditView, wxView) -bool TextEditView::OnCreate(wxDocument *doc, long flags) +BEGIN_EVENT_TABLE(TextEditView, wxView) + EVT_MENU(wxID_COPY, TextEditView::OnCopy) + EVT_MENU(wxID_PASTE, TextEditView::OnPaste) + EVT_MENU(wxID_SELECTALL, TextEditView::OnSelectAll) +END_EVENT_TABLE() + +bool TextEditView::OnCreate(wxDocument *doc, long WXUNUSED(flags)) { - frame = wxGetApp().CreateChildFrame(doc, this, FALSE); - - int width, height; - frame->GetClientSize(&width, &height); - textsw = new MyTextWindow(this, frame, wxPoint(0, 0), wxSize(width, height), wxTE_MULTILINE); - frame->SetTitle("TextEditView"); - -#ifdef __X__ - // X seems to require a forced resize - int x, y; - frame->GetSize(&x, &y); - frame->SetSize(x, y); -#endif + m_frame = wxGetApp().CreateChildFrame(doc, this, false); + m_text = new wxTextCtrl(m_frame, wxID_ANY, "", + wxPoint(0, 0), m_frame->GetClientSize(), + wxTE_MULTILINE); - frame->Show(TRUE); - Activate(TRUE); - - return TRUE; -} + m_frame->SetTitle("Text View"); + m_frame->Show(true); -// Handled by wxTextWindow -void TextEditView::OnDraw(wxDC *dc) -{ + Activate(true); + + return true; } -void TextEditView::OnUpdate(wxView *sender, wxObject *hint) +void TextEditView::OnDraw(wxDC *WXUNUSED(dc)) { + // nothing to do here, wxTextCtrl draws itself } bool TextEditView::OnClose(bool deleteWindow) { - if (!GetDocument()->Close()) - return FALSE; - - Activate(FALSE); - - if (deleteWindow) - { - delete frame; - return TRUE; - } - return TRUE; + if ( !GetDocument()->Close() ) + return false; + + Activate(false); + + if ( wxGetApp().GetMode() == MyApp::Mode_Single ) + { + m_text->Clear(); + } + else // not single window mode + { + if ( deleteWindow ) + wxDELETE(m_frame); + } + + return true; } -/* - * Window implementations - */ +// ---------------------------------------------------------------------------- +// MyCanvas implementation +// ---------------------------------------------------------------------------- BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow) EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent) END_EVENT_TABLE() // Define a constructor for my canvas -MyCanvas::MyCanvas(wxView *v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style): - wxScrolledWindow(frame, -1, pos, size, style) +MyCanvas::MyCanvas(wxView *view, wxWindow *parent) + : wxScrolledWindow(parent, wxID_ANY, wxPoint(0, 0), parent->GetClientSize()) { - view = v; + m_view = view; + m_currentSegment = NULL; + m_lastMousePos = wxDefaultPosition; + + SetCursor(wxCursor(wxCURSOR_PENCIL)); + + // this is completely arbitrary and is done just for illustration purposes + SetVirtualSize(1000, 1000); + SetScrollRate(20, 20); + + SetBackgroundColour(*wxWHITE); +} + +MyCanvas::~MyCanvas() +{ + delete m_currentSegment; } // Define the repainting behaviour void MyCanvas::OnDraw(wxDC& dc) { - if (view) - view->OnDraw(& dc); + if ( m_view ) + m_view->OnDraw(& dc); } -// This implements a tiny doodling program. Drag the mouse using -// the left button. +// This implements a tiny doodling program. Drag the mouse using the left +// button. void MyCanvas::OnMouseEvent(wxMouseEvent& event) { - if (!view) - return; - - static DoodleSegment *currentSegment = NULL; + if ( !m_view ) + return; - wxClientDC dc(this); - PrepareDC(dc); + wxClientDC dc(this); + PrepareDC(dc); - dc.SetPen(*wxBLACK_PEN); + dc.SetPen(*wxBLACK_PEN); - wxPoint pt(event.GetLogicalPosition(dc)); + const wxPoint pt(event.GetLogicalPosition(dc)); - if (currentSegment && event.LeftUp()) - { - if (currentSegment->lines.Number() == 0) + // is this the end of the current segment? + if ( m_currentSegment && event.LeftUp() ) { - delete currentSegment; - currentSegment = NULL; + if ( !m_currentSegment->IsEmpty() ) + { + // We've got a valid segment on mouse left up, so store it. + DrawingDocument * const + doc = wxStaticCast(m_view->GetDocument(), DrawingDocument); + + doc->GetCommandProcessor()->Submit( + new DrawingAddSegmentCommand(doc, *m_currentSegment)); + + doc->Modify(true); + } + + delete m_currentSegment; + m_currentSegment = NULL; } - else + + // is this the start of a new segment? + if ( m_lastMousePos != wxDefaultPosition && event.Dragging() ) { - // We've got a valid segment on mouse left up, so store it. - DrawingDocument *doc = (DrawingDocument *)view->GetDocument(); + if ( !m_currentSegment ) + m_currentSegment = new DoodleSegment; - doc->GetCommandProcessor()->Submit(new DrawingCommand("Add Segment", DOODLE_ADD, doc, currentSegment)); + m_currentSegment->AddLine(m_lastMousePos, pt); - view->GetDocument()->Modify(TRUE); - currentSegment = NULL; + dc.DrawLine(m_lastMousePos, pt); } - } - - if (xpos > -1 && ypos > -1 && event.Dragging()) - { - if (!currentSegment) - currentSegment = new DoodleSegment; - - DoodleLine *newLine = new DoodleLine; - newLine->x1 = xpos; newLine->y1 = ypos; - newLine->x2 = pt.x; newLine->y2 = pt.y; - currentSegment->lines.Append(newLine); - - dc.DrawLine(xpos, ypos, pt.x, pt.y); - } - xpos = pt.x; - ypos = pt.y; + + m_lastMousePos = pt; +} + +// ---------------------------------------------------------------------------- +// wxImageCanvas implementation +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxImageCanvas, wxScrolledWindow) +END_EVENT_TABLE() + +// Define a constructor for my canvas +wxImageCanvas::wxImageCanvas(wxView* view, wxWindow* parent) + : wxScrolledWindow(parent, wxID_ANY, wxPoint(0, 0), parent->GetClientSize()) +{ + m_view = view; } -// Define a constructor for my text subwindow -MyTextWindow::MyTextWindow(wxView *v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style): - wxTextCtrl(frame, -1, "", pos, size, style) +// Define the repainting behaviour +void wxImageCanvas::OnDraw(wxDC& dc) { - view = v; + if ( m_view ) + m_view->OnDraw(& dc); } +// ---------------------------------------------------------------------------- +// wxImageView implementation +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxImageView, wxView) + +BEGIN_EVENT_TABLE(wxImageView, wxView) +END_EVENT_TABLE() + +wxImageDocument* wxImageView::GetDocument() +{ + return wxStaticCast(wxView::GetDocument(), wxImageDocument); +} + +bool wxImageView::OnCreate(wxDocument* doc, long WXUNUSED(flags)) +{ + m_frame = wxGetApp().CreateChildFrame(doc, this, false); + m_frame->SetTitle("Image View"); + m_canvas = new wxImageCanvas(this, m_frame); + m_frame->Show(true); + Activate(true); + return true; +} + +void wxImageView::OnUpdate(wxView* sender, wxObject* hint) +{ + wxView::OnUpdate(sender, hint); + const wxImage* image = GetDocument()->GetImage(); + if (image->IsOk()) + { + m_canvas->SetScrollbars( 1, 1, image->GetWidth(), image->GetHeight() ); + } +} + +void wxImageView::OnDraw(wxDC* dc) +{ + const wxImage* image = GetDocument()->GetImage(); + if (image->IsOk()) + { + dc->DrawBitmap(wxBitmap(*image), 0, 0); + } +} + +bool wxImageView::OnClose(bool deleteWindow) +{ + if ( !GetDocument()->Close() ) + return false; + + Activate(false); + + if ( wxGetApp().GetMode() == MyApp::Mode_Single ) + { + GetDocument()->DeleteContents(); + } + else // not single window mode + { + if ( deleteWindow ) + wxDELETE(m_frame); + } + return true; +}