]> git.saurik.com Git - wxWidgets.git/blame - samples/docview/view.cpp
override DoSetValue() to avoid unnecessary clipboard operations, fixes #14369
[wxWidgets.git] / samples / docview / view.cpp
CommitLineData
457814b5 1/////////////////////////////////////////////////////////////////////////////
2d1df0fc
VZ
2// Name: samples/docview/view.cpp
3// Purpose: View classes implementation
457814b5 4// Author: Julian Smart
2d1df0fc 5// Modified by: Vadim Zeitlin: merge with the MDI version and general cleanup
457814b5
JS
6// Created: 04/01/98
7// RCS-ID: $Id$
2d1df0fc
VZ
8// Copyright: (c) 1998 Julian Smart
9// (c) 2008 Vadim Zeitlin
526954c5 10// Licence: wxWindows licence
457814b5
JS
11/////////////////////////////////////////////////////////////////////////////
12
457814b5
JS
13// For compilers that support precompilation, includes "wx/wx.h".
14#include "wx/wxprec.h"
15
16#ifdef __BORLANDC__
2d1df0fc 17 #pragma hdrstop
457814b5
JS
18#endif
19
20#ifndef WX_PRECOMP
2d1df0fc 21 #include "wx/wx.h"
457814b5
JS
22#endif
23
e4b19d9b 24#if !wxUSE_DOC_VIEW_ARCHITECTURE
2d1df0fc 25 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
457814b5
JS
26#endif
27
28#include "docview.h"
29#include "doc.h"
30#include "view.h"
31
2d1df0fc
VZ
32// ----------------------------------------------------------------------------
33// DrawingView implementation
34// ----------------------------------------------------------------------------
457814b5 35
2d1df0fc 36IMPLEMENT_DYNAMIC_CLASS(DrawingView, wxView)
457814b5
JS
37
38BEGIN_EVENT_TABLE(DrawingView, wxView)
2d1df0fc 39 EVT_MENU(wxID_CUT, DrawingView::OnCut)
457814b5
JS
40END_EVENT_TABLE()
41
42// What to do when a view is created. Creates actual
43// windows for displaying the view.
9b341e6f 44bool DrawingView::OnCreate(wxDocument *doc, long flags)
457814b5 45{
9b341e6f
VZ
46 if ( !wxView::OnCreate(doc, flags) )
47 return false;
48
2d1df0fc
VZ
49 MyApp& app = wxGetApp();
50 if ( app.GetMode() != MyApp::Mode_Single )
f6bcfd97 51 {
2d1df0fc 52 // create a new window and canvas inside it
9b341e6f
VZ
53 wxFrame* frame = app.CreateChildFrame(this, true);
54 wxASSERT(frame == GetFrame());
55 m_canvas = new MyCanvas(this);
c346d3d2 56 frame->Show();
f6bcfd97 57 }
2d1df0fc 58 else // single document mode
f6bcfd97 59 {
2d1df0fc 60 // reuse the existing window and canvas
2d1df0fc
VZ
61 m_canvas = app.GetMainWindowCanvas();
62 m_canvas->SetView(this);
6bdf5153 63
f6bcfd97 64 // Initialize the edit menu Undo and Redo items
2d1df0fc 65 doc->GetCommandProcessor()->SetEditMenu(app.GetMainWindowEditMenu());
f6bcfd97
BP
66 doc->GetCommandProcessor()->Initialize();
67 }
6bdf5153 68
f2aea0d1 69 return true;
457814b5
JS
70}
71
2d1df0fc
VZ
72// Sneakily gets used for default print/preview as well as drawing on the
73// screen.
457814b5
JS
74void DrawingView::OnDraw(wxDC *dc)
75{
f6bcfd97 76 dc->SetPen(*wxBLACK_PEN);
6bdf5153 77
2d1df0fc
VZ
78 // simply draw all lines of all segments
79 const DoodleSegments& segments = GetDocument()->GetSegments();
80 for ( DoodleSegments::const_iterator i = segments.begin();
81 i != segments.end();
82 ++i )
f6bcfd97 83 {
2d1df0fc 84 const DoodleLines& lines = i->GetLines();
ce00f59b 85 for ( DoodleLines::const_iterator j = lines.begin();
2d1df0fc
VZ
86 j != lines.end();
87 ++j )
88 {
89 const DoodleLine& line = *j;
90
91 dc->DrawLine(line.x1, line.y1, line.x2, line.y2);
92 }
f6bcfd97 93 }
457814b5
JS
94}
95
6bdf5153
VZ
96DrawingDocument* DrawingView::GetDocument()
97{
98 return wxStaticCast(wxView::GetDocument(), DrawingDocument);
99}
100
f37f49b6 101void DrawingView::OnUpdate(wxView* sender, wxObject* hint)
457814b5 102{
f37f49b6 103 wxView::OnUpdate(sender, hint);
2d1df0fc 104 if ( m_canvas )
6bdf5153 105 m_canvas->Refresh();
457814b5
JS
106}
107
108// Clean up windows used for displaying the view.
109bool DrawingView::OnClose(bool deleteWindow)
110{
ab5259d9 111 if ( !wxView::OnClose(deleteWindow) )
f2aea0d1 112 return false;
6bdf5153 113
f2aea0d1 114 Activate(false);
6bdf5153 115
2d1df0fc
VZ
116 // Clear the canvas in single-window mode in which it stays alive
117 if ( wxGetApp().GetMode() == MyApp::Mode_Single )
118 {
119 m_canvas->ClearBackground();
120 m_canvas->ResetView();
121 m_canvas = NULL;
122
9b341e6f
VZ
123 if (GetFrame())
124 wxStaticCast(GetFrame(), wxFrame)->SetTitle(wxTheApp->GetAppDisplayName());
2d1df0fc
VZ
125 }
126 else // not single window mode
f6bcfd97 127 {
2d1df0fc 128 if ( deleteWindow )
9b341e6f
VZ
129 {
130 GetFrame()->Destroy();
131 SetFrame(NULL);
132 }
f6bcfd97 133 }
f2aea0d1 134 return true;
457814b5
JS
135}
136
e3e65dac 137void DrawingView::OnCut(wxCommandEvent& WXUNUSED(event) )
457814b5 138{
2d1df0fc
VZ
139 DrawingDocument * const doc = GetDocument();
140
141 doc->GetCommandProcessor()->Submit(new DrawingRemoveSegmentCommand(doc));
457814b5
JS
142}
143
2d1df0fc
VZ
144// ----------------------------------------------------------------------------
145// TextEditView implementation
146// ----------------------------------------------------------------------------
147
457814b5
JS
148IMPLEMENT_DYNAMIC_CLASS(TextEditView, wxView)
149
4e553af1
VZ
150BEGIN_EVENT_TABLE(TextEditView, wxView)
151 EVT_MENU(wxID_COPY, TextEditView::OnCopy)
152 EVT_MENU(wxID_PASTE, TextEditView::OnPaste)
153 EVT_MENU(wxID_SELECTALL, TextEditView::OnSelectAll)
154END_EVENT_TABLE()
155
9b341e6f 156bool TextEditView::OnCreate(wxDocument *doc, long flags)
457814b5 157{
9b341e6f
VZ
158 if ( !wxView::OnCreate(doc, flags) )
159 return false;
2d1df0fc 160
9b341e6f
VZ
161 wxFrame* frame = wxGetApp().CreateChildFrame(this, false);
162 wxASSERT(frame == GetFrame());
163 m_text = new wxTextCtrl(frame, wxID_ANY, "",
164 wxDefaultPosition, wxDefaultSize,
165 wxTE_MULTILINE);
166 frame->Show();
6bdf5153 167
f2aea0d1 168 return true;
457814b5
JS
169}
170
2d1df0fc 171void TextEditView::OnDraw(wxDC *WXUNUSED(dc))
457814b5 172{
2d1df0fc 173 // nothing to do here, wxTextCtrl draws itself
457814b5
JS
174}
175
176bool TextEditView::OnClose(bool deleteWindow)
177{
ab5259d9 178 if ( !wxView::OnClose(deleteWindow) )
f2aea0d1 179 return false;
6bdf5153 180
f2aea0d1 181 Activate(false);
6bdf5153 182
2d1df0fc 183 if ( wxGetApp().GetMode() == MyApp::Mode_Single )
f6bcfd97 184 {
2d1df0fc 185 m_text->Clear();
f6bcfd97 186 }
2d1df0fc
VZ
187 else // not single window mode
188 {
189 if ( deleteWindow )
9b341e6f
VZ
190 {
191 GetFrame()->Destroy();
192 SetFrame(NULL);
193 }
2d1df0fc 194 }
f2aea0d1 195 return true;
457814b5
JS
196}
197
2d1df0fc
VZ
198// ----------------------------------------------------------------------------
199// MyCanvas implementation
200// ----------------------------------------------------------------------------
457814b5
JS
201
202BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
203 EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
204END_EVENT_TABLE()
205
206// Define a constructor for my canvas
2d1df0fc 207MyCanvas::MyCanvas(wxView *view, wxWindow *parent)
9b341e6f 208 : wxScrolledWindow(parent ? parent : view->GetFrame())
457814b5 209{
6bdf5153 210 m_view = view;
2d1df0fc
VZ
211 m_currentSegment = NULL;
212 m_lastMousePos = wxDefaultPosition;
213
214 SetCursor(wxCursor(wxCURSOR_PENCIL));
215
216 // this is completely arbitrary and is done just for illustration purposes
217 SetVirtualSize(1000, 1000);
218 SetScrollRate(20, 20);
219
220 SetBackgroundColour(*wxWHITE);
221}
222
223MyCanvas::~MyCanvas()
224{
225 delete m_currentSegment;
457814b5
JS
226}
227
228// Define the repainting behaviour
229void MyCanvas::OnDraw(wxDC& dc)
230{
2d1df0fc 231 if ( m_view )
6bdf5153 232 m_view->OnDraw(& dc);
457814b5
JS
233}
234
2d1df0fc
VZ
235// This implements a tiny doodling program. Drag the mouse using the left
236// button.
457814b5
JS
237void MyCanvas::OnMouseEvent(wxMouseEvent& event)
238{
2d1df0fc 239 if ( !m_view )
f6bcfd97 240 return;
6bdf5153 241
f6bcfd97
BP
242 wxClientDC dc(this);
243 PrepareDC(dc);
6bdf5153 244
f6bcfd97 245 dc.SetPen(*wxBLACK_PEN);
6bdf5153 246
2d1df0fc 247 const wxPoint pt(event.GetLogicalPosition(dc));
6bdf5153 248
2d1df0fc
VZ
249 // is this the end of the current segment?
250 if ( m_currentSegment && event.LeftUp() )
457814b5 251 {
2d1df0fc 252 if ( !m_currentSegment->IsEmpty() )
f6bcfd97
BP
253 {
254 // We've got a valid segment on mouse left up, so store it.
2d1df0fc
VZ
255 DrawingDocument * const
256 doc = wxStaticCast(m_view->GetDocument(), DrawingDocument);
6bdf5153 257
2d1df0fc
VZ
258 doc->GetCommandProcessor()->Submit(
259 new DrawingAddSegmentCommand(doc, *m_currentSegment));
6bdf5153 260
2d1df0fc 261 doc->Modify(true);
f6bcfd97 262 }
2d1df0fc 263
5276b0a5 264 wxDELETE(m_currentSegment);
457814b5 265 }
6bdf5153 266
2d1df0fc
VZ
267 // is this the start of a new segment?
268 if ( m_lastMousePos != wxDefaultPosition && event.Dragging() )
457814b5 269 {
2d1df0fc
VZ
270 if ( !m_currentSegment )
271 m_currentSegment = new DoodleSegment;
6bdf5153 272
2d1df0fc 273 m_currentSegment->AddLine(m_lastMousePos, pt);
6bdf5153 274
2d1df0fc 275 dc.DrawLine(m_lastMousePos, pt);
457814b5 276 }
457814b5 277
2d1df0fc 278 m_lastMousePos = pt;
457814b5
JS
279}
280
f37f49b6 281// ----------------------------------------------------------------------------
2d4a03f8 282// ImageCanvas implementation
f37f49b6
JS
283// ----------------------------------------------------------------------------
284
f37f49b6 285// Define a constructor for my canvas
9b341e6f
VZ
286ImageCanvas::ImageCanvas(wxView* view)
287 : wxScrolledWindow(view->GetFrame())
f37f49b6
JS
288{
289 m_view = view;
9b341e6f 290 SetScrollRate( 10, 10 );
f37f49b6
JS
291}
292
293// Define the repainting behaviour
2d4a03f8 294void ImageCanvas::OnDraw(wxDC& dc)
f37f49b6
JS
295{
296 if ( m_view )
297 m_view->OnDraw(& dc);
298}
299
300// ----------------------------------------------------------------------------
2d4a03f8 301// ImageView implementation
f37f49b6
JS
302// ----------------------------------------------------------------------------
303
2d4a03f8 304IMPLEMENT_DYNAMIC_CLASS(ImageView, wxView)
f37f49b6 305
2d4a03f8 306ImageDocument* ImageView::GetDocument()
f37f49b6 307{
2d4a03f8 308 return wxStaticCast(wxView::GetDocument(), ImageDocument);
f37f49b6
JS
309}
310
9b341e6f 311bool ImageView::OnCreate(wxDocument* doc, long flags)
f37f49b6 312{
9b341e6f
VZ
313 if ( !wxView::OnCreate(doc, flags) )
314 return false;
315
316 wxFrame* frame = wxGetApp().CreateChildFrame(this, false);
317 wxASSERT(frame == GetFrame());
318 m_canvas = new ImageCanvas(this);
319 frame->Show();
320
f37f49b6
JS
321 return true;
322}
323
2d4a03f8 324void ImageView::OnUpdate(wxView* sender, wxObject* hint)
f37f49b6
JS
325{
326 wxView::OnUpdate(sender, hint);
2d4a03f8
VZ
327 wxImage image = GetDocument()->GetImage();
328 if ( image.IsOk() )
f37f49b6 329 {
2d4a03f8 330 m_canvas->SetVirtualSize(image.GetWidth(), image.GetHeight());
f37f49b6
JS
331 }
332}
333
2d4a03f8 334void ImageView::OnDraw(wxDC* dc)
f37f49b6 335{
2d4a03f8
VZ
336 wxImage image = GetDocument()->GetImage();
337 if ( image.IsOk() )
f37f49b6 338 {
11c278c4 339 dc->DrawBitmap(wxBitmap(image), 0, 0, true /* use mask */);
f37f49b6
JS
340 }
341}
342
2d4a03f8 343bool ImageView::OnClose(bool deleteWindow)
f37f49b6 344{
ab5259d9 345 if ( !wxView::OnClose(deleteWindow) )
f37f49b6
JS
346 return false;
347
348 Activate(false);
349
350 if ( wxGetApp().GetMode() == MyApp::Mode_Single )
351 {
352 GetDocument()->DeleteContents();
353 }
354 else // not single window mode
355 {
356 if ( deleteWindow )
9b341e6f
VZ
357 {
358 GetFrame()->Destroy();
359 SetFrame(NULL);
360 }
f37f49b6
JS
361 }
362 return true;
363}
364
4db97e24
VZ
365// ----------------------------------------------------------------------------
366// ImageDetailsView
367// ----------------------------------------------------------------------------
368
369ImageDetailsView::ImageDetailsView(ImageDetailsDocument *doc)
370 : wxView()
371{
372 SetDocument(doc);
373
374 m_frame = wxGetApp().CreateChildFrame(this, false);
375 m_frame->SetTitle("Image Details");
376
377 wxPanel * const panel = new wxPanel(m_frame);
378 wxFlexGridSizer * const sizer = new wxFlexGridSizer(2, wxSize(5, 5));
379 const wxSizerFlags
380 flags = wxSizerFlags().Align(wxALIGN_CENTRE_VERTICAL).Border();
381
382 sizer->Add(new wxStaticText(panel, wxID_ANY, "Image &file:"), flags);
383 sizer->Add(new wxStaticText(panel, wxID_ANY, doc->GetFilename()), flags);
384
385 sizer->Add(new wxStaticText(panel, wxID_ANY, "Image &type:"), flags);
386 wxString typeStr;
387 switch ( doc->GetType() )
388 {
389 case wxBITMAP_TYPE_PNG:
390 typeStr = "PNG";
391 break;
392
393 case wxBITMAP_TYPE_JPEG:
394 typeStr = "JPEG";
395 break;
396
397 default:
398 typeStr = "Unknown";
399 }
400 sizer->Add(new wxStaticText(panel, wxID_ANY, typeStr), flags);
401
402 sizer->Add(new wxStaticText(panel, wxID_ANY, "Image &size:"), flags);
403 wxSize size = doc->GetSize();
404 sizer->Add(new wxStaticText(panel, wxID_ANY,
405 wxString::Format("%d*%d", size.x, size.y)),
406 flags);
407
408 sizer->Add(new wxStaticText(panel, wxID_ANY, "Number of unique &colours:"),
409 flags);
410 sizer->Add(new wxStaticText(panel, wxID_ANY,
411 wxString::Format("%lu", doc->GetNumColours())),
412 flags);
413
414 sizer->Add(new wxStaticText(panel, wxID_ANY, "Uses &alpha:"), flags);
415 sizer->Add(new wxStaticText(panel, wxID_ANY,
416 doc->HasAlpha() ? "Yes" : "No"), flags);
417
418 panel->SetSizer(sizer);
419 m_frame->SetClientSize(panel->GetBestSize());
420 m_frame->Show(true);
421}
422
423void ImageDetailsView::OnDraw(wxDC * WXUNUSED(dc))
424{
425 // nothing to do here, we use controls to show our information
426}
427
428bool ImageDetailsView::OnClose(bool deleteWindow)
429{
430 if ( wxGetApp().GetMode() != MyApp::Mode_Single && deleteWindow )
431 {
432 delete m_frame;
433 m_frame = NULL;
434 }
435
436 return true;
437}