]> git.saurik.com Git - wxWidgets.git/blob - samples/dragimag/dragimag.cpp
This is how wxPlotWindow would look like with the
[wxWidgets.git] / samples / dragimag / dragimag.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dragimag.cpp
3 // Purpose: wxDragImage sample
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 28/2/2000
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif
22
23 #include "wx/image.h"
24
25 // Under Windows, change this to 1
26 // to use wxGenericDragImage
27
28 #define wxUSE_GENERIC_DRAGIMAGE 1
29
30 #if wxUSE_GENERIC_DRAGIMAGE
31 #include "wx/generic/dragimgg.h"
32 #define wxDragImage wxGenericDragImage
33 #else
34 #include "wx/dragimag.h"
35 #endif
36
37 #include "dragimag.h"
38
39 #if defined(__WXGTK__) || defined(__WXMOTIF__)
40 #include "mondrian.xpm"
41 #include "dragicon.xpm"
42 #endif
43
44 // main program
45
46 IMPLEMENT_APP(MyApp)
47
48 // MyCanvas
49
50 IMPLEMENT_CLASS(MyCanvas, wxScrolledWindow)
51
52 BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
53 EVT_PAINT(MyCanvas::OnPaint)
54 EVT_ERASE_BACKGROUND(MyCanvas::OnEraseBackground)
55 EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
56 END_EVENT_TABLE()
57
58 MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id,
59 const wxPoint &pos, const wxSize &size )
60 : wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER )
61 {
62 SetBackgroundColour(* wxWHITE);
63
64 SetCursor(wxCursor(wxCURSOR_ARROW));
65
66 m_dragMode = TEST_DRAG_NONE;
67 m_draggedShape = (DragShape*) NULL;
68 m_dragImage = (wxDragImage*) NULL;
69 m_currentlyHighlighted = (DragShape*) NULL;
70 }
71
72 MyCanvas::~MyCanvas()
73 {
74 ClearShapes();
75
76 if (m_dragImage)
77 delete m_dragImage;
78 }
79
80 void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
81 {
82 wxPaintDC dc( this );
83 PrepareDC( dc );
84
85 DrawShapes(dc);
86
87 }
88
89 void MyCanvas::OnEraseBackground(wxEraseEvent& event)
90 {
91 if (wxGetApp().GetBackgroundBitmap().Ok())
92 {
93 wxSize sz = GetClientSize();
94 wxRect rect(0, 0, sz.x, sz.y);
95
96 if (event.GetDC())
97 {
98 wxGetApp().TileBitmap(rect, *(event.GetDC()), wxGetApp().GetBackgroundBitmap());
99 }
100 else
101 {
102 wxClientDC dc(this);
103 wxGetApp().TileBitmap(rect, dc, wxGetApp().GetBackgroundBitmap());
104 }
105 }
106 else
107 event.Skip(); // The official way of doing it
108 }
109
110 void MyCanvas::OnMouseEvent(wxMouseEvent& event)
111 {
112 if (event.LeftDown())
113 {
114 DragShape* shape = FindShape(event.GetPosition());
115 if (shape)
116 {
117 // We tentatively start dragging, but wait for
118 // mouse movement before dragging properly.
119
120 m_dragMode = TEST_DRAG_START;
121 m_dragStartPos = event.GetPosition();
122 m_draggedShape = shape;
123 }
124 }
125 else if (event.LeftUp() && m_dragMode != TEST_DRAG_NONE)
126 {
127 // Finish dragging
128
129 m_dragMode = TEST_DRAG_NONE;
130
131 if (!m_draggedShape || !m_dragImage)
132 return;
133
134 wxPoint newPos(m_draggedShape->GetPosition().x + (event.GetPosition().x - m_dragStartPos.x),
135 m_draggedShape->GetPosition().y + (event.GetPosition().y - m_dragStartPos.y));
136
137 m_draggedShape->SetPosition(newPos);
138
139 m_dragImage->Hide();
140 m_dragImage->EndDrag();
141 delete m_dragImage;
142 m_dragImage = NULL;
143
144 wxClientDC dc(this);
145 if (m_currentlyHighlighted)
146 {
147 m_currentlyHighlighted->Draw(dc);
148 }
149 m_draggedShape->SetShow(TRUE);
150 m_draggedShape->Draw(dc);
151
152 m_currentlyHighlighted = (DragShape*) NULL;
153
154 m_draggedShape = (DragShape*) NULL;
155 }
156 else if (event.Dragging() && m_dragMode != TEST_DRAG_NONE)
157 {
158 if (m_dragMode == TEST_DRAG_START)
159 {
160 // We will start dragging if we've moved beyond a couple of pixels
161
162 int tolerance = 2;
163 int dx = abs(event.GetPosition().x - m_dragStartPos.x);
164 int dy = abs(event.GetPosition().y - m_dragStartPos.y);
165 if (dx <= tolerance && dy <= tolerance)
166 return;
167
168 wxPoint newPos(m_draggedShape->GetPosition().x + (event.GetPosition().x - m_dragStartPos.x),
169 m_draggedShape->GetPosition().y + (event.GetPosition().y - m_dragStartPos.y));
170
171 // Start the drag.
172 m_dragMode = TEST_DRAG_DRAGGING;
173
174 if (m_dragImage)
175 delete m_dragImage;
176
177 // Erase the dragged shape from the canvas
178 m_draggedShape->SetShow(FALSE);
179 wxClientDC dc(this);
180 EraseShape(m_draggedShape, dc);
181 DrawShapes(dc);
182
183 switch (m_draggedShape->GetDragMethod())
184 {
185 case SHAPE_DRAG_BITMAP:
186 {
187 wxPoint hotSpot(event.GetPosition().x - newPos.x, event.GetPosition().y - newPos.y);
188 m_dragImage = new wxDragImage(m_draggedShape->GetBitmap(), wxCursor(wxCURSOR_HAND), hotSpot);
189 break;
190 }
191 case SHAPE_DRAG_TEXT:
192 {
193 wxPoint hotSpot(event.GetPosition().x - newPos.x, event.GetPosition().y - newPos.y);
194 m_dragImage = new wxDragImage("Dragging some test text", wxCursor(wxCURSOR_HAND), hotSpot);
195 break;
196 }
197 case SHAPE_DRAG_ICON:
198 {
199 wxPoint hotSpot(event.GetPosition().x - newPos.x, event.GetPosition().y - newPos.y);
200
201 // Can anyone explain why this test is necessary,
202 // to prevent a gcc error?
203 #ifdef __WXMOTIF__
204 wxIcon icon(dragicon_xpm);
205 #else
206 wxIcon icon(wxICON(dragicon));
207 #endif
208
209 m_dragImage = new wxDragImage(icon, wxCursor(wxCURSOR_HAND), hotSpot);
210 break;
211 }
212 }
213
214 bool fullScreen = FALSE;
215 if (wxGetApp().GetUseScreen())
216 {
217 newPos = ClientToScreen(newPos);
218 fullScreen = TRUE;
219 }
220
221 bool retValue;
222
223 if (fullScreen)
224 // This line uses the whole screen...
225 retValue = m_dragImage->BeginDrag(wxPoint(0, 0), this, TRUE);
226 // while this line restricts dragging to the parent frame.
227 // retValue = m_dragImage->BeginDrag(wxPoint(0, 0), this, GetParent());
228 else
229 retValue = m_dragImage->BeginDrag(wxPoint(0, 0), this);
230
231 if (!retValue)
232 {
233 delete m_dragImage;
234 m_dragImage = (wxDragImage*) NULL;
235 m_dragMode = TEST_DRAG_NONE;
236 }
237 m_dragImage->Move(newPos);
238 m_dragImage->Show();
239 }
240 else if (m_dragMode == TEST_DRAG_DRAGGING)
241 {
242 // We're currently dragging. See if we're over another shape.
243 DragShape* onShape = FindShape(event.GetPosition());
244
245 bool mustUnhighlightOld = FALSE;
246 bool mustHighlightNew = FALSE;
247
248 if (m_currentlyHighlighted)
249 {
250 if ((onShape == (DragShape*) NULL) || (m_currentlyHighlighted != onShape))
251 mustUnhighlightOld = TRUE;
252 }
253
254 if (onShape && (onShape != m_currentlyHighlighted) && onShape->IsShown())
255 mustHighlightNew = TRUE;
256
257 if (mustUnhighlightOld || mustHighlightNew)
258 m_dragImage->Hide();
259
260 // Now with the drag image switched off, we can change the window contents.
261
262 if (mustUnhighlightOld)
263 {
264 wxClientDC clientDC(this);
265 m_currentlyHighlighted->Draw(clientDC);
266 m_currentlyHighlighted = (DragShape*) NULL;
267 }
268 if (mustHighlightNew)
269 {
270 wxClientDC clientDC(this);
271 m_currentlyHighlighted = onShape;
272 m_currentlyHighlighted->Draw(clientDC, wxINVERT);
273 }
274
275 wxPoint newPos(m_draggedShape->GetPosition().x + (event.GetPosition().x - m_dragStartPos.x),
276 m_draggedShape->GetPosition().y + (event.GetPosition().y - m_dragStartPos.y));
277
278 if (wxGetApp().GetUseScreen())
279 {
280 newPos = ClientToScreen(newPos);
281 }
282
283 // Move and show the image again
284 m_dragImage->Move(newPos);
285
286 if (mustUnhighlightOld || mustHighlightNew)
287 m_dragImage->Show();
288 }
289 }
290 }
291
292 void MyCanvas::DrawShapes(wxDC& dc)
293 {
294 wxNode* node = m_displayList.First();
295 while (node)
296 {
297 DragShape* shape = (DragShape*) node->Data();
298 if (shape->IsShown())
299 shape->Draw(dc);
300 node = node->Next();
301 }
302 }
303
304 void MyCanvas::EraseShape(DragShape* shape, wxDC& dc)
305 {
306 wxSize sz = GetClientSize();
307 wxRect rect(0, 0, sz.x, sz.y);
308
309 wxRect rect2(shape->GetRect());
310 dc.SetClippingRegion(rect2.x, rect2.y, rect2.width, rect2.height);
311
312 wxGetApp().TileBitmap(rect, dc, wxGetApp().GetBackgroundBitmap());
313
314 dc.DestroyClippingRegion();
315 }
316
317 void MyCanvas::ClearShapes()
318 {
319 wxNode* node = m_displayList.First();
320 while (node)
321 {
322 DragShape* shape = (DragShape*) node->Data();
323 delete shape;
324 node = node->Next();
325 }
326 m_displayList.Clear();
327 }
328
329 DragShape* MyCanvas::FindShape(const wxPoint& pt) const
330 {
331 wxNode* node = m_displayList.First();
332 while (node)
333 {
334 DragShape* shape = (DragShape*) node->Data();
335 if (shape->HitTest(pt))
336 return shape;
337 node = node->Next();
338 }
339 return (DragShape*) NULL;
340 }
341
342 // MyFrame
343
344 IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
345
346 BEGIN_EVENT_TABLE(MyFrame,wxFrame)
347 EVT_MENU (wxID_ABOUT, MyFrame::OnAbout)
348 EVT_MENU (wxID_EXIT, MyFrame::OnQuit)
349 END_EVENT_TABLE()
350
351 MyFrame::MyFrame()
352 : wxFrame( (wxFrame *)NULL, -1, "wxDragImage sample",
353 wxPoint(20,20), wxSize(470,360) )
354 {
355 wxMenu *file_menu = new wxMenu();
356 file_menu->Append( wxID_ABOUT, "&About...");
357 file_menu->Append( TEST_USE_SCREEN, "&Use whole screen for dragging", "Use whole screen", TRUE);
358 file_menu->Append( wxID_EXIT, "E&xit");
359
360 wxMenuBar *menu_bar = new wxMenuBar();
361 menu_bar->Append(file_menu, "&File");
362
363 SetMenuBar( menu_bar );
364
365 CreateStatusBar(2);
366 int widths[] = { -1, 100 };
367 SetStatusWidths( 2, widths );
368
369 m_canvas = new MyCanvas( this, -1, wxPoint(0,0), wxSize(10,10) );
370 }
371
372 void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )
373 {
374 Close( TRUE );
375 }
376
377 void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) )
378 {
379 (void)wxMessageBox( "wxDragImage demo\n"
380 "Julian Smart (c) 2000",
381 "About wxDragImage Demo", wxICON_INFORMATION | wxOK );
382 }
383
384 //-----------------------------------------------------------------------------
385 // MyApp
386 //-----------------------------------------------------------------------------
387
388 BEGIN_EVENT_TABLE(MyApp, wxApp)
389 EVT_MENU(TEST_USE_SCREEN, MyApp::OnUseScreen)
390 END_EVENT_TABLE()
391
392 MyApp::MyApp()
393 {
394 // Drag across whole screen
395 m_useScreen = FALSE;
396 }
397
398 bool MyApp::OnInit()
399 {
400 #if wxUSE_LIBPNG
401 wxImage::AddHandler( new wxPNGHandler );
402 #endif
403
404 wxImage image;
405 if (image.LoadFile("backgrnd.png", wxBITMAP_TYPE_PNG))
406 {
407 m_background = image.ConvertToBitmap();
408 }
409
410
411 MyFrame *frame = new MyFrame();
412
413 wxString rootName("shape0");
414
415 int i;
416 for (i = 1; i < 4; i++)
417 {
418 wxString filename;
419 filename.Printf("%s%d.png", (const char*) rootName, i);
420 if (image.LoadFile(filename, wxBITMAP_TYPE_PNG))
421 {
422 DragShape* newShape = new DragShape(image.ConvertToBitmap());
423 newShape->SetPosition(wxPoint(i*50, i*50));
424
425 if (i == 2)
426 newShape->SetDragMethod(SHAPE_DRAG_TEXT);
427 else if (i == 3)
428 newShape->SetDragMethod(SHAPE_DRAG_ICON);
429 else
430 newShape->SetDragMethod(SHAPE_DRAG_BITMAP);
431 frame->GetCanvas()->GetDisplayList().Append(newShape);
432 }
433 }
434
435 #if 0
436 // Under Motif or GTK, this demonstrates that
437 // wxScreenDC only gets the root window content.
438 // We need to be able to copy the overall content
439 // for full-screen dragging to work.
440 int w, h;
441 wxDisplaySize(& w, & h);
442 wxBitmap bitmap(w, h);
443
444 wxScreenDC dc;
445 wxMemoryDC memDC;
446 memDC.SelectObject(bitmap);
447 memDC.Blit(0, 0, w, h, & dc, 0, 0);
448 memDC.SelectObject(wxNullBitmap);
449 m_background = bitmap;
450 #endif
451
452 frame->Show( TRUE );
453
454 return TRUE;
455 }
456
457 bool MyApp::TileBitmap(const wxRect& rect, wxDC& dc, wxBitmap& bitmap)
458 {
459 int w = bitmap.GetWidth();
460 int h = bitmap.GetHeight();
461
462 int i, j;
463 for (i = rect.x; i < rect.x + rect.width; i += w)
464 {
465 for (j = rect.y; j < rect.y + rect.height; j+= h)
466 dc.DrawBitmap(bitmap, i, j);
467 }
468 return TRUE;
469 }
470
471 void MyApp::OnUseScreen(wxCommandEvent& event)
472 {
473 m_useScreen = !m_useScreen;
474 }
475
476 // DragShape
477
478 DragShape::DragShape(const wxBitmap& bitmap)
479 {
480 m_bitmap = bitmap;
481 m_pos.x = 0;
482 m_pos.y = 0;
483 m_dragMethod = SHAPE_DRAG_BITMAP;
484 m_show = TRUE;
485 }
486
487 DragShape::~DragShape()
488 {
489 }
490
491 bool DragShape::HitTest(const wxPoint& pt) const
492 {
493 wxRect rect(GetRect());
494 return rect.Inside(pt.x, pt.y);
495 }
496
497 bool DragShape::Draw(wxDC& dc, int op)
498 {
499 if (m_bitmap.Ok())
500 {
501 wxMemoryDC memDC;
502 memDC.SelectObject(m_bitmap);
503
504 dc.Blit(m_pos.x, m_pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight(),
505 & memDC, 0, 0, op, TRUE);
506
507 return TRUE;
508 }
509 else
510 return FALSE;
511 }
512