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