]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: samples/docview/view.cpp | |
3 | // Purpose: View classes implementation | |
4 | // Author: Julian Smart | |
5 | // Modified by: Vadim Zeitlin: merge with the MDI version and general cleanup | |
6 | // Created: 04/01/98 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) 1998 Julian Smart | |
9 | // (c) 2008 Vadim Zeitlin | |
10 | // Licence: wxWindows licence | |
11 | ///////////////////////////////////////////////////////////////////////////// | |
12 | ||
13 | // For compilers that support precompilation, includes "wx/wx.h". | |
14 | #include "wx/wxprec.h" | |
15 | ||
16 | #ifdef __BORLANDC__ | |
17 | #pragma hdrstop | |
18 | #endif | |
19 | ||
20 | #ifndef WX_PRECOMP | |
21 | #include "wx/wx.h" | |
22 | #endif | |
23 | ||
24 | #if !wxUSE_DOC_VIEW_ARCHITECTURE | |
25 | #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h! | |
26 | #endif | |
27 | ||
28 | #include "docview.h" | |
29 | #include "doc.h" | |
30 | #include "view.h" | |
31 | ||
32 | // ---------------------------------------------------------------------------- | |
33 | // DrawingView implementation | |
34 | // ---------------------------------------------------------------------------- | |
35 | ||
36 | IMPLEMENT_DYNAMIC_CLASS(DrawingView, wxView) | |
37 | ||
38 | BEGIN_EVENT_TABLE(DrawingView, wxView) | |
39 | EVT_MENU(wxID_CUT, DrawingView::OnCut) | |
40 | END_EVENT_TABLE() | |
41 | ||
42 | // What to do when a view is created. Creates actual | |
43 | // windows for displaying the view. | |
44 | bool DrawingView::OnCreate(wxDocument *doc, long flags) | |
45 | { | |
46 | if ( !wxView::OnCreate(doc, flags) ) | |
47 | return false; | |
48 | ||
49 | MyApp& app = wxGetApp(); | |
50 | if ( app.GetMode() != MyApp::Mode_Single ) | |
51 | { | |
52 | // create a new window and canvas inside it | |
53 | wxFrame* frame = app.CreateChildFrame(this, true); | |
54 | wxASSERT(frame == GetFrame()); | |
55 | m_canvas = new MyCanvas(this); | |
56 | frame->Show(); | |
57 | } | |
58 | else // single document mode | |
59 | { | |
60 | // reuse the existing window and canvas | |
61 | m_canvas = app.GetMainWindowCanvas(); | |
62 | m_canvas->SetView(this); | |
63 | ||
64 | // Initialize the edit menu Undo and Redo items | |
65 | doc->GetCommandProcessor()->SetEditMenu(app.GetMainWindowEditMenu()); | |
66 | doc->GetCommandProcessor()->Initialize(); | |
67 | } | |
68 | ||
69 | return true; | |
70 | } | |
71 | ||
72 | // Sneakily gets used for default print/preview as well as drawing on the | |
73 | // screen. | |
74 | void DrawingView::OnDraw(wxDC *dc) | |
75 | { | |
76 | dc->SetPen(*wxBLACK_PEN); | |
77 | ||
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 ) | |
83 | { | |
84 | const DoodleLines& lines = i->GetLines(); | |
85 | for ( DoodleLines::const_iterator j = lines.begin(); | |
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 | } | |
93 | } | |
94 | } | |
95 | ||
96 | DrawingDocument* DrawingView::GetDocument() | |
97 | { | |
98 | return wxStaticCast(wxView::GetDocument(), DrawingDocument); | |
99 | } | |
100 | ||
101 | void DrawingView::OnUpdate(wxView* sender, wxObject* hint) | |
102 | { | |
103 | wxView::OnUpdate(sender, hint); | |
104 | if ( m_canvas ) | |
105 | m_canvas->Refresh(); | |
106 | } | |
107 | ||
108 | // Clean up windows used for displaying the view. | |
109 | bool DrawingView::OnClose(bool deleteWindow) | |
110 | { | |
111 | if ( !wxView::OnClose(deleteWindow) ) | |
112 | return false; | |
113 | ||
114 | Activate(false); | |
115 | ||
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 | ||
123 | if (GetFrame()) | |
124 | wxStaticCast(GetFrame(), wxFrame)->SetTitle(wxTheApp->GetAppDisplayName()); | |
125 | } | |
126 | else // not single window mode | |
127 | { | |
128 | if ( deleteWindow ) | |
129 | { | |
130 | GetFrame()->Destroy(); | |
131 | SetFrame(NULL); | |
132 | } | |
133 | } | |
134 | return true; | |
135 | } | |
136 | ||
137 | void DrawingView::OnCut(wxCommandEvent& WXUNUSED(event) ) | |
138 | { | |
139 | DrawingDocument * const doc = GetDocument(); | |
140 | ||
141 | doc->GetCommandProcessor()->Submit(new DrawingRemoveSegmentCommand(doc)); | |
142 | } | |
143 | ||
144 | // ---------------------------------------------------------------------------- | |
145 | // TextEditView implementation | |
146 | // ---------------------------------------------------------------------------- | |
147 | ||
148 | IMPLEMENT_DYNAMIC_CLASS(TextEditView, wxView) | |
149 | ||
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 | ||
156 | bool TextEditView::OnCreate(wxDocument *doc, long flags) | |
157 | { | |
158 | if ( !wxView::OnCreate(doc, flags) ) | |
159 | return false; | |
160 | ||
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(); | |
167 | ||
168 | return true; | |
169 | } | |
170 | ||
171 | void TextEditView::OnDraw(wxDC *WXUNUSED(dc)) | |
172 | { | |
173 | // nothing to do here, wxTextCtrl draws itself | |
174 | } | |
175 | ||
176 | bool TextEditView::OnClose(bool deleteWindow) | |
177 | { | |
178 | if ( !wxView::OnClose(deleteWindow) ) | |
179 | return false; | |
180 | ||
181 | Activate(false); | |
182 | ||
183 | if ( wxGetApp().GetMode() == MyApp::Mode_Single ) | |
184 | { | |
185 | m_text->Clear(); | |
186 | } | |
187 | else // not single window mode | |
188 | { | |
189 | if ( deleteWindow ) | |
190 | { | |
191 | GetFrame()->Destroy(); | |
192 | SetFrame(NULL); | |
193 | } | |
194 | } | |
195 | return true; | |
196 | } | |
197 | ||
198 | // ---------------------------------------------------------------------------- | |
199 | // MyCanvas implementation | |
200 | // ---------------------------------------------------------------------------- | |
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 | |
207 | MyCanvas::MyCanvas(wxView *view, wxWindow *parent) | |
208 | : wxScrolledWindow(parent ? parent : view->GetFrame()) | |
209 | { | |
210 | m_view = view; | |
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; | |
226 | } | |
227 | ||
228 | // Define the repainting behaviour | |
229 | void MyCanvas::OnDraw(wxDC& dc) | |
230 | { | |
231 | if ( m_view ) | |
232 | m_view->OnDraw(& dc); | |
233 | } | |
234 | ||
235 | // This implements a tiny doodling program. Drag the mouse using the left | |
236 | // button. | |
237 | void MyCanvas::OnMouseEvent(wxMouseEvent& event) | |
238 | { | |
239 | if ( !m_view ) | |
240 | return; | |
241 | ||
242 | wxClientDC dc(this); | |
243 | PrepareDC(dc); | |
244 | ||
245 | dc.SetPen(*wxBLACK_PEN); | |
246 | ||
247 | const wxPoint pt(event.GetLogicalPosition(dc)); | |
248 | ||
249 | // is this the end of the current segment? | |
250 | if ( m_currentSegment && event.LeftUp() ) | |
251 | { | |
252 | if ( !m_currentSegment->IsEmpty() ) | |
253 | { | |
254 | // We've got a valid segment on mouse left up, so store it. | |
255 | DrawingDocument * const | |
256 | doc = wxStaticCast(m_view->GetDocument(), DrawingDocument); | |
257 | ||
258 | doc->GetCommandProcessor()->Submit( | |
259 | new DrawingAddSegmentCommand(doc, *m_currentSegment)); | |
260 | ||
261 | doc->Modify(true); | |
262 | } | |
263 | ||
264 | wxDELETE(m_currentSegment); | |
265 | } | |
266 | ||
267 | // is this the start of a new segment? | |
268 | if ( m_lastMousePos != wxDefaultPosition && event.Dragging() ) | |
269 | { | |
270 | if ( !m_currentSegment ) | |
271 | m_currentSegment = new DoodleSegment; | |
272 | ||
273 | m_currentSegment->AddLine(m_lastMousePos, pt); | |
274 | ||
275 | dc.DrawLine(m_lastMousePos, pt); | |
276 | } | |
277 | ||
278 | m_lastMousePos = pt; | |
279 | } | |
280 | ||
281 | // ---------------------------------------------------------------------------- | |
282 | // ImageCanvas implementation | |
283 | // ---------------------------------------------------------------------------- | |
284 | ||
285 | // Define a constructor for my canvas | |
286 | ImageCanvas::ImageCanvas(wxView* view) | |
287 | : wxScrolledWindow(view->GetFrame()) | |
288 | { | |
289 | m_view = view; | |
290 | SetScrollRate( 10, 10 ); | |
291 | } | |
292 | ||
293 | // Define the repainting behaviour | |
294 | void ImageCanvas::OnDraw(wxDC& dc) | |
295 | { | |
296 | if ( m_view ) | |
297 | m_view->OnDraw(& dc); | |
298 | } | |
299 | ||
300 | // ---------------------------------------------------------------------------- | |
301 | // ImageView implementation | |
302 | // ---------------------------------------------------------------------------- | |
303 | ||
304 | IMPLEMENT_DYNAMIC_CLASS(ImageView, wxView) | |
305 | ||
306 | ImageDocument* ImageView::GetDocument() | |
307 | { | |
308 | return wxStaticCast(wxView::GetDocument(), ImageDocument); | |
309 | } | |
310 | ||
311 | bool ImageView::OnCreate(wxDocument* doc, long flags) | |
312 | { | |
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 | ||
321 | return true; | |
322 | } | |
323 | ||
324 | void ImageView::OnUpdate(wxView* sender, wxObject* hint) | |
325 | { | |
326 | wxView::OnUpdate(sender, hint); | |
327 | wxImage image = GetDocument()->GetImage(); | |
328 | if ( image.IsOk() ) | |
329 | { | |
330 | m_canvas->SetVirtualSize(image.GetWidth(), image.GetHeight()); | |
331 | } | |
332 | } | |
333 | ||
334 | void ImageView::OnDraw(wxDC* dc) | |
335 | { | |
336 | wxImage image = GetDocument()->GetImage(); | |
337 | if ( image.IsOk() ) | |
338 | { | |
339 | dc->DrawBitmap(wxBitmap(image), 0, 0, true /* use mask */); | |
340 | } | |
341 | } | |
342 | ||
343 | bool ImageView::OnClose(bool deleteWindow) | |
344 | { | |
345 | if ( !wxView::OnClose(deleteWindow) ) | |
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 ) | |
357 | { | |
358 | GetFrame()->Destroy(); | |
359 | SetFrame(NULL); | |
360 | } | |
361 | } | |
362 | return true; | |
363 | } | |
364 | ||
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 | } |