]> git.saurik.com Git - wxWidgets.git/blob - samples/docview/view.cpp
Support using GetTextExtent() with empty string to get descent in wxOSX.
[wxWidgets.git] / samples / docview / view.cpp
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 }