]>
Commit | Line | Data |
---|---|---|
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 | 36 | IMPLEMENT_DYNAMIC_CLASS(DrawingView, wxView) |
457814b5 JS |
37 | |
38 | BEGIN_EVENT_TABLE(DrawingView, wxView) | |
2d1df0fc | 39 | EVT_MENU(wxID_CUT, DrawingView::OnCut) |
457814b5 JS |
40 | END_EVENT_TABLE() |
41 | ||
42 | // What to do when a view is created. Creates actual | |
43 | // windows for displaying the view. | |
9b341e6f | 44 | bool 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 |
74 | void 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 |
96 | DrawingDocument* DrawingView::GetDocument() |
97 | { | |
98 | return wxStaticCast(wxView::GetDocument(), DrawingDocument); | |
99 | } | |
100 | ||
f37f49b6 | 101 | void 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. | |
109 | bool 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 | 137 | void 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 |
148 | IMPLEMENT_DYNAMIC_CLASS(TextEditView, wxView) |
149 | ||
4e553af1 VZ |
150 | BEGIN_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) | |
154 | END_EVENT_TABLE() | |
155 | ||
9b341e6f | 156 | bool 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 | 171 | void TextEditView::OnDraw(wxDC *WXUNUSED(dc)) |
457814b5 | 172 | { |
2d1df0fc | 173 | // nothing to do here, wxTextCtrl draws itself |
457814b5 JS |
174 | } |
175 | ||
176 | bool 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 | |
202 | BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow) | |
203 | EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent) | |
204 | END_EVENT_TABLE() | |
205 | ||
206 | // Define a constructor for my canvas | |
2d1df0fc | 207 | MyCanvas::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 | ||
223 | MyCanvas::~MyCanvas() | |
224 | { | |
225 | delete m_currentSegment; | |
457814b5 JS |
226 | } |
227 | ||
228 | // Define the repainting behaviour | |
229 | void 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 |
237 | void 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 |
286 | ImageCanvas::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 | 294 | void 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 | 304 | IMPLEMENT_DYNAMIC_CLASS(ImageView, wxView) |
f37f49b6 | 305 | |
2d4a03f8 | 306 | ImageDocument* ImageView::GetDocument() |
f37f49b6 | 307 | { |
2d4a03f8 | 308 | return wxStaticCast(wxView::GetDocument(), ImageDocument); |
f37f49b6 JS |
309 | } |
310 | ||
9b341e6f | 311 | bool 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 | 324 | void 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 | 334 | void 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 | 343 | bool 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 | ||
369 | ImageDetailsView::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 | ||
423 | void ImageDetailsView::OnDraw(wxDC * WXUNUSED(dc)) | |
424 | { | |
425 | // nothing to do here, we use controls to show our information | |
426 | } | |
427 | ||
428 | bool 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 | } |