X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6bdf5153fef0772f7dca91c67073dee8f87e467d..814028444d682b23af3809227cd485f4bebc1286:/samples/docview/view.cpp diff --git a/samples/docview/view.cpp b/samples/docview/view.cpp index d2a02dccdb..5b3743fd90 100644 --- a/samples/docview/view.cpp +++ b/samples/docview/view.cpp @@ -1,97 +1,95 @@ ///////////////////////////////////////////////////////////////////////////// -// 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 -// Licence: wxWindows license +// Copyright: (c) 1998 Julian Smart +// (c) 2008 Vadim Zeitlin +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // 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 !wxUSE_DOC_VIEW_ARCHITECTURE -#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h! + #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 -static float xpos = -1; -static 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 WXUNUSED(flags) ) +bool DrawingView::OnCreate(wxDocument *doc, long flags) { - if (!singleWindowMode) + if ( !wxView::OnCreate(doc, flags) ) + return false; + + MyApp& app = wxGetApp(); + if ( app.GetMode() != MyApp::Mode_Single ) { - // Multiple windows - m_frame = wxGetApp().CreateChildFrame(doc, this, true); - m_frame->SetTitle(wxT("DrawingView")); - - m_canvas = GetMainFrame()->CreateCanvas(this, m_frame); -#ifdef __X__ - // X seems to require a forced resize - int x, y; - m_frame->GetSize(&x, &y); - m_frame->SetSize(wxDefaultCoord, wxDefaultCoord, x, y); -#endif - m_frame->Show(true); + // create a new window and canvas inside it + wxFrame* frame = app.CreateChildFrame(this, true); + wxASSERT(frame == GetFrame()); + m_canvas = new MyCanvas(this); + frame->Show(); } - else + else // single document mode { - // Single-window mode - m_frame = GetMainFrame(); - m_canvas = GetMainFrame()->m_canvas; - m_canvas->m_view = 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); + // reuse the existing window and canvas + m_canvas = app.GetMainWindowCanvas(); + m_canvas->SetView(this); // Initialize the edit menu Undo and Redo items - doc->GetCommandProcessor()->SetEditMenu(((MyFrame*)m_frame)->m_editMenu); + 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); - wxList::compatibility_iterator node = GetDocument()->GetDoodleSegments().GetFirst(); - while (node) + // simply draw all lines of all segments + const DoodleSegments& segments = GetDocument()->GetSegments(); + for ( DoodleSegments::const_iterator i = segments.begin(); + i != segments.end(); + ++i ) { - DoodleSegment *seg = (DoodleSegment *)node->GetData(); - seg->Draw(dc); - node = node->GetNext(); + 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); + } } } @@ -100,202 +98,340 @@ DrawingDocument* DrawingView::GetDocument() return wxStaticCast(wxView::GetDocument(), DrawingDocument); } -void DrawingView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint)) +void DrawingView::OnUpdate(wxView* sender, wxObject* hint) { - if (m_canvas) + wxView::OnUpdate(sender, hint); + if ( m_canvas ) m_canvas->Refresh(); - -/* Is the following necessary? -#ifdef __WXMSW__ - if (canvas) - canvas->Refresh(); -#else - if (canvas) - { - wxClientDC dc(canvas); - dc.Clear(); - OnDraw(& dc); - } -#endif -*/ } // Clean up windows used for displaying the view. bool DrawingView::OnClose(bool deleteWindow) { - if (!GetDocument()->Close()) + if ( !wxView::OnClose(deleteWindow) ) return false; - // Clear the canvas in case we're in single-window mode, - // and the canvas stays. - m_canvas->ClearBackground(); - m_canvas->m_view = NULL; - m_canvas = NULL; - - wxString s(wxTheApp->GetAppDisplayName()); - if (m_frame) - m_frame->SetTitle(s); - - SetFrame(NULL); - Activate(false); - if (deleteWindow && !singleWindowMode) + // Clear the canvas in single-window mode in which it stays alive + if ( wxGetApp().GetMode() == MyApp::Mode_Single ) { - delete m_frame; - return true; + m_canvas->ClearBackground(); + m_canvas->ResetView(); + m_canvas = NULL; + + if (GetFrame()) + wxStaticCast(GetFrame(), wxFrame)->SetTitle(wxTheApp->GetAppDisplayName()); + } + else // not single window mode + { + if ( deleteWindow ) + { + GetFrame()->Destroy(); + SetFrame(NULL); + } } return true; } void DrawingView::OnCut(wxCommandEvent& WXUNUSED(event) ) { - DrawingDocument* doc = GetDocument(); - doc->GetCommandProcessor()->Submit(new DrawingCommand(wxT("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 WXUNUSED(flags) ) -{ - m_frame = wxGetApp().CreateChildFrame(doc, this, false); +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() - wxSize size = m_frame->GetClientSize(); - m_textsw = new MyTextWindow(this, m_frame, wxPoint(0, 0), size, wxTE_MULTILINE); - m_frame->SetTitle(wxT("TextEditView")); +bool TextEditView::OnCreate(wxDocument *doc, long flags) +{ + if ( !wxView::OnCreate(doc, flags) ) + return false; -#ifdef __X__ - // X seems to require a forced resize - int x, y; - frame->GetSize(&x, &y); - frame->SetSize(wxDefaultCoord, wxDefaultCoord, x, y); -#endif - - m_frame->Show(true); - Activate(true); + wxFrame* frame = wxGetApp().CreateChildFrame(this, false); + wxASSERT(frame == GetFrame()); + m_text = new wxTextCtrl(frame, wxID_ANY, "", + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE); + frame->Show(); return true; } -// Handled by wxTextWindow -void TextEditView::OnDraw(wxDC *WXUNUSED(dc) ) -{ -} - -void TextEditView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) ) +void TextEditView::OnDraw(wxDC *WXUNUSED(dc)) { + // nothing to do here, wxTextCtrl draws itself } bool TextEditView::OnClose(bool deleteWindow) { - if (!GetDocument()->Close()) + if ( !wxView::OnClose(deleteWindow) ) return false; Activate(false); - if (deleteWindow) + if ( wxGetApp().GetMode() == MyApp::Mode_Single ) { - wxDELETE(m_frame) - return true; + m_text->Clear(); } - return true; -} - -bool TextEditView::ProcessEvent(wxEvent& event) -{ - bool processed = false; - if (!processed) switch (event.GetId()) + else // not single window mode { - case wxID_COPY: - case wxID_PASTE: - case wxID_SELECTALL: - processed = m_textsw->ProcessEvent(event); - break; + if ( deleteWindow ) + { + GetFrame()->Destroy(); + SetFrame(NULL); + } } - if (!processed) processed = wxView::ProcessEvent(event); - return processed; + 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(DrawingView* view, wxFrame* frame, const wxPoint& pos, const wxSize& size, const long style): - wxScrolledWindow(frame, wxID_ANY, pos, size, style) +MyCanvas::MyCanvas(wxView *view, wxWindow *parent) + : wxScrolledWindow(parent ? parent : view->GetFrame()) { 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 (m_view) + 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 (!m_view) + if ( !m_view ) return; - static DoodleSegment *currentSegment = NULL; - wxClientDC dc(this); PrepareDC(dc); dc.SetPen(*wxBLACK_PEN); - wxPoint pt(event.GetLogicalPosition(dc)); + const wxPoint pt(event.GetLogicalPosition(dc)); - if (currentSegment && event.LeftUp()) + // is this the end of the current segment? + if ( m_currentSegment && event.LeftUp() ) { - if (currentSegment->m_lines.GetCount() == 0) - { - delete currentSegment; - currentSegment = NULL; - } - else + if ( !m_currentSegment->IsEmpty() ) { // We've got a valid segment on mouse left up, so store it. - DrawingDocument* doc = m_view->GetDocument(); + DrawingDocument * const + doc = wxStaticCast(m_view->GetDocument(), DrawingDocument); - doc->GetCommandProcessor()->Submit(new DrawingCommand(wxT("Add Segment"), DOODLE_ADD, doc, currentSegment)); + doc->GetCommandProcessor()->Submit( + new DrawingAddSegmentCommand(doc, *m_currentSegment)); - m_view->GetDocument()->Modify(true); - currentSegment = NULL; + doc->Modify(true); } + + wxDELETE(m_currentSegment); } - if ( (xpos > -1) && (ypos > -1) && event.Dragging()) + // is this the start of a new segment? + if ( m_lastMousePos != wxDefaultPosition && event.Dragging() ) { - if (!currentSegment) - currentSegment = new DoodleSegment; + if ( !m_currentSegment ) + m_currentSegment = new DoodleSegment; - DoodleLine *newLine = new DoodleLine; - newLine->x1 = (long)xpos; - newLine->y1 = (long)ypos; - newLine->x2 = pt.x; - newLine->y2 = pt.y; - currentSegment->m_lines.Append(newLine); + m_currentSegment->AddLine(m_lastMousePos, pt); - dc.DrawLine( (long)xpos, (long)ypos, pt.x, pt.y); + dc.DrawLine(m_lastMousePos, pt); } - xpos = pt.x; - ypos = pt.y; + + m_lastMousePos = pt; } -// Define a constructor for my text subwindow -MyTextWindow::MyTextWindow(wxView* view, wxFrame* frame, const wxPoint& pos, const wxSize& size, const long style): - wxTextCtrl(frame, wxID_ANY, wxEmptyString, pos, size, style) +// ---------------------------------------------------------------------------- +// ImageCanvas implementation +// ---------------------------------------------------------------------------- + +// Define a constructor for my canvas +ImageCanvas::ImageCanvas(wxView* view) + : wxScrolledWindow(view->GetFrame()) { m_view = view; + SetScrollRate( 10, 10 ); +} + +// Define the repainting behaviour +void ImageCanvas::OnDraw(wxDC& dc) +{ + if ( m_view ) + m_view->OnDraw(& dc); } +// ---------------------------------------------------------------------------- +// ImageView implementation +// ---------------------------------------------------------------------------- +IMPLEMENT_DYNAMIC_CLASS(ImageView, wxView) + +ImageDocument* ImageView::GetDocument() +{ + return wxStaticCast(wxView::GetDocument(), ImageDocument); +} + +bool ImageView::OnCreate(wxDocument* doc, long flags) +{ + if ( !wxView::OnCreate(doc, flags) ) + return false; + + wxFrame* frame = wxGetApp().CreateChildFrame(this, false); + wxASSERT(frame == GetFrame()); + m_canvas = new ImageCanvas(this); + frame->Show(); + + return true; +} + +void ImageView::OnUpdate(wxView* sender, wxObject* hint) +{ + wxView::OnUpdate(sender, hint); + wxImage image = GetDocument()->GetImage(); + if ( image.IsOk() ) + { + m_canvas->SetVirtualSize(image.GetWidth(), image.GetHeight()); + } +} + +void ImageView::OnDraw(wxDC* dc) +{ + wxImage image = GetDocument()->GetImage(); + if ( image.IsOk() ) + { + dc->DrawBitmap(wxBitmap(image), 0, 0, true /* use mask */); + } +} + +bool ImageView::OnClose(bool deleteWindow) +{ + if ( !wxView::OnClose(deleteWindow) ) + return false; + + Activate(false); + + if ( wxGetApp().GetMode() == MyApp::Mode_Single ) + { + GetDocument()->DeleteContents(); + } + else // not single window mode + { + if ( deleteWindow ) + { + GetFrame()->Destroy(); + SetFrame(NULL); + } + } + return true; +} + +// ---------------------------------------------------------------------------- +// ImageDetailsView +// ---------------------------------------------------------------------------- + +ImageDetailsView::ImageDetailsView(ImageDetailsDocument *doc) + : wxView() +{ + SetDocument(doc); + + m_frame = wxGetApp().CreateChildFrame(this, false); + m_frame->SetTitle("Image Details"); + + wxPanel * const panel = new wxPanel(m_frame); + wxFlexGridSizer * const sizer = new wxFlexGridSizer(2, wxSize(5, 5)); + const wxSizerFlags + flags = wxSizerFlags().Align(wxALIGN_CENTRE_VERTICAL).Border(); + + sizer->Add(new wxStaticText(panel, wxID_ANY, "Image &file:"), flags); + sizer->Add(new wxStaticText(panel, wxID_ANY, doc->GetFilename()), flags); + + sizer->Add(new wxStaticText(panel, wxID_ANY, "Image &type:"), flags); + wxString typeStr; + switch ( doc->GetType() ) + { + case wxBITMAP_TYPE_PNG: + typeStr = "PNG"; + break; + + case wxBITMAP_TYPE_JPEG: + typeStr = "JPEG"; + break; + + default: + typeStr = "Unknown"; + } + sizer->Add(new wxStaticText(panel, wxID_ANY, typeStr), flags); + + sizer->Add(new wxStaticText(panel, wxID_ANY, "Image &size:"), flags); + wxSize size = doc->GetSize(); + sizer->Add(new wxStaticText(panel, wxID_ANY, + wxString::Format("%d*%d", size.x, size.y)), + flags); + + sizer->Add(new wxStaticText(panel, wxID_ANY, "Number of unique &colours:"), + flags); + sizer->Add(new wxStaticText(panel, wxID_ANY, + wxString::Format("%lu", doc->GetNumColours())), + flags); + + sizer->Add(new wxStaticText(panel, wxID_ANY, "Uses &alpha:"), flags); + sizer->Add(new wxStaticText(panel, wxID_ANY, + doc->HasAlpha() ? "Yes" : "No"), flags); + + panel->SetSizer(sizer); + m_frame->SetClientSize(panel->GetBestSize()); + m_frame->Show(true); +} + +void ImageDetailsView::OnDraw(wxDC * WXUNUSED(dc)) +{ + // nothing to do here, we use controls to show our information +} + +bool ImageDetailsView::OnClose(bool deleteWindow) +{ + if ( wxGetApp().GetMode() != MyApp::Mode_Single && deleteWindow ) + { + delete m_frame; + m_frame = NULL; + } + + return true; +}