use BMPs and npt PNGs under MSW
[wxWidgets.git] / samples / dnd / dnd.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dnd.cpp
3 // Purpose: Drag and drop sample
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright:
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #endif
21
22 #ifdef __WXMOTIF__
23 #error Sorry, drag and drop is not yet implemented on wxMotif.
24 #endif
25
26 #include "wx/intl.h"
27 #include "wx/log.h"
28
29 #include "wx/dnd.h"
30 #include "wx/dirdlg.h"
31 #include "wx/filedlg.h"
32 #include "wx/image.h"
33 #include "wx/clipbrd.h"
34
35 #if defined(__WXGTK__) || defined(__WXMOTIF__)
36 #include "mondrian.xpm"
37 #endif
38
39 // ----------------------------------------------------------------------------
40 // Derive two simple classes which just put in the listbox the strings (text or
41 // file names) we drop on them
42 // ----------------------------------------------------------------------------
43
44 typedef long wxDropPointCoord;
45
46 class DnDText : public wxTextDropTarget
47 {
48 public:
49 DnDText(wxListBox *pOwner) { m_pOwner = pOwner; }
50
51 virtual bool OnDropText(wxDropPointCoord x, wxDropPointCoord y,
52 const wxChar* psz);
53
54 private:
55 wxListBox *m_pOwner;
56 };
57
58 class DnDFile : public wxFileDropTarget
59 {
60 public:
61 DnDFile(wxListBox *pOwner) { m_pOwner = pOwner; }
62
63 virtual bool OnDropFiles(wxDropPointCoord x, wxDropPointCoord y,
64 size_t nFiles, const wxChar* const aszFiles[] );
65
66 private:
67 wxListBox *m_pOwner;
68 };
69
70 // ----------------------------------------------------------------------------
71 // Define a new application type
72 // ----------------------------------------------------------------------------
73
74 class DnDApp : public wxApp
75 {
76 public:
77 bool OnInit();
78 };
79
80 IMPLEMENT_APP(DnDApp);
81
82 // ----------------------------------------------------------------------------
83 // Define a new frame type
84 // ----------------------------------------------------------------------------
85 class DnDFrame : public wxFrame
86 {
87 public:
88 DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
89 ~DnDFrame();
90
91 void OnPaint(wxPaintEvent& event);
92 void OnQuit (wxCommandEvent& event);
93 void OnAbout(wxCommandEvent& event);
94 void OnDrag (wxCommandEvent& event);
95 void OnHelp (wxCommandEvent& event);
96 void OnLogClear(wxCommandEvent& event);
97 void OnCopy(wxCommandEvent& event);
98 void OnPaste(wxCommandEvent& event);
99 void OnCopyBitmap(wxCommandEvent& event);
100 void OnPasteBitmap(wxCommandEvent& event);
101 void OnClipboardHasText(wxCommandEvent& event);
102 void OnClipboardHasBitmap(wxCommandEvent& event);
103
104 void OnLeftDown(wxMouseEvent& event);
105 void OnRightDown(wxMouseEvent& event);
106
107 DECLARE_EVENT_TABLE()
108
109 private:
110 wxListBox *m_ctrlFile,
111 *m_ctrlText;
112 wxTextCtrl *m_ctrlLog;
113
114 wxLog *m_pLog, *m_pLogPrev;
115
116 wxString m_strText;
117 wxBitmap m_bitmap;
118 };
119
120 // ----------------------------------------------------------------------------
121 // IDs for the menu commands
122 // ----------------------------------------------------------------------------
123
124 enum
125 {
126 Menu_Quit = 1,
127 Menu_Drag,
128 Menu_About = 101,
129 Menu_Help,
130 Menu_Clear,
131 Menu_Copy,
132 Menu_Paste,
133 Menu_CopyBitmap,
134 Menu_PasteBitmap,
135 Menu_HasText,
136 Menu_HasBitmap
137 };
138
139 BEGIN_EVENT_TABLE(DnDFrame, wxFrame)
140 EVT_MENU(Menu_Quit, DnDFrame::OnQuit)
141 EVT_MENU(Menu_About, DnDFrame::OnAbout)
142 EVT_MENU(Menu_Drag, DnDFrame::OnDrag)
143 EVT_MENU(Menu_Help, DnDFrame::OnHelp)
144 EVT_MENU(Menu_Clear, DnDFrame::OnLogClear)
145 EVT_MENU(Menu_Copy, DnDFrame::OnCopy)
146 EVT_MENU(Menu_Paste, DnDFrame::OnPaste)
147 EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap)
148 EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap)
149 EVT_MENU(Menu_HasText, DnDFrame::OnClipboardHasText)
150 EVT_MENU(Menu_HasBitmap, DnDFrame::OnClipboardHasBitmap)
151
152 EVT_LEFT_DOWN( DnDFrame::OnLeftDown)
153 EVT_RIGHT_DOWN( DnDFrame::OnRightDown)
154 EVT_PAINT( DnDFrame::OnPaint)
155 END_EVENT_TABLE()
156
157 // `Main program' equivalent, creating windows and returning main app frame
158 bool DnDApp::OnInit()
159 {
160 #if wxUSE_LIBPNG
161 wxImage::AddHandler( new wxPNGHandler );
162 #endif
163
164 // create the main frame window
165 DnDFrame *frame = new DnDFrame((wxFrame *) NULL,
166 "Drag-and-Drop/Clipboard wxWindows Sample",
167 50, 50, 450, 340);
168
169 // activate it
170 frame->Show(TRUE);
171
172 SetTopWindow(frame);
173
174 return TRUE;
175 }
176
177 DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
178 : wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h)),
179 m_strText("wxWindows drag & drop works :-)")
180
181 {
182 // frame icon and status bar
183 SetIcon(wxICON(mondrian));
184
185 CreateStatusBar();
186
187 // construct menu
188 wxMenu *file_menu = new wxMenu;
189 file_menu->Append(Menu_Drag, "&Test drag...");
190 file_menu->AppendSeparator();
191 file_menu->Append(Menu_Quit, "E&xit");
192
193 wxMenu *log_menu = new wxMenu;
194 log_menu->Append(Menu_Clear, "Clear");
195
196 wxMenu *help_menu = new wxMenu;
197 help_menu->Append(Menu_Help, "&Help...");
198 help_menu->AppendSeparator();
199 help_menu->Append(Menu_About, "&About");
200
201 wxMenu *clip_menu = new wxMenu;
202 clip_menu->Append(Menu_Copy, "&Copy text\tCtrl+C");
203 clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V");
204 clip_menu->AppendSeparator();
205 clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap");
206 clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap");
207 clip_menu->AppendSeparator();
208 clip_menu->Append(Menu_HasText, "Clipboard has &text\tCtrl+T");
209 clip_menu->Append(Menu_HasBitmap, "Clipboard has a &bitmap\tCtrl+B");
210
211 wxMenuBar *menu_bar = new wxMenuBar;
212 menu_bar->Append(file_menu, "&File");
213 menu_bar->Append(log_menu, "&Log");
214 menu_bar->Append(clip_menu, "&Clipboard");
215 menu_bar->Append(help_menu, "&Help");
216
217 SetMenuBar(menu_bar);
218
219 // make a panel with 3 subwindows
220 wxPoint pos(0, 0);
221 wxSize size(400, 200);
222
223 wxString strFile("Drop files here!"), strText("Drop text on me");
224
225 m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile, wxLB_HSCROLL | wxLB_ALWAYS_SB );
226 m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText, wxLB_HSCROLL | wxLB_ALWAYS_SB );
227
228 m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size,
229 wxTE_MULTILINE | wxTE_READONLY |
230 wxSUNKEN_BORDER );
231 // redirect log messages to the text window (don't forget to delete it!)
232 m_pLog = new wxLogTextCtrl(m_ctrlLog);
233 m_pLogPrev = wxLog::SetActiveTarget(m_pLog);
234
235 // associate drop targets with 2 text controls
236 m_ctrlFile->SetDropTarget(new DnDFile(m_ctrlFile));
237 m_ctrlText->SetDropTarget(new DnDText(m_ctrlText));
238
239 wxLayoutConstraints *c;
240
241 // Top-left listbox
242 c = new wxLayoutConstraints;
243 c->left.SameAs(this, wxLeft);
244 c->top.SameAs(this, wxTop);
245 c->right.PercentOf(this, wxRight, 50);
246 c->height.PercentOf(this, wxHeight, 30);
247 m_ctrlFile->SetConstraints(c);
248
249 // Top-right listbox
250 c = new wxLayoutConstraints;
251 c->left.SameAs (m_ctrlFile, wxRight);
252 c->top.SameAs (this, wxTop);
253 c->right.SameAs (this, wxRight);
254 c->height.PercentOf(this, wxHeight, 30);
255 m_ctrlText->SetConstraints(c);
256
257 // Lower text control
258 c = new wxLayoutConstraints;
259 c->left.SameAs (this, wxLeft);
260 c->right.SameAs (this, wxRight);
261 c->height.PercentOf(this, wxHeight, 30);
262 c->top.SameAs(m_ctrlText, wxBottom);
263 m_ctrlLog->SetConstraints(c);
264
265 SetAutoLayout(TRUE);
266 }
267
268 void DnDFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
269 {
270 Close(TRUE);
271 }
272
273 void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
274 {
275 int w = 0;
276 int h = 0;
277 GetClientSize( &w, &h );
278
279 wxPaintDC dc(this);
280 dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) );
281 dc.DrawText( "Drag text from here!", 20, h-50 );
282
283 if (m_bitmap.Ok())
284 dc.DrawBitmap( m_bitmap, 280, h-120, TRUE );
285 }
286
287 void DnDFrame::OnClipboardHasText(wxCommandEvent& WXUNUSED(event))
288 {
289 if ( !wxTheClipboard->Open() )
290 {
291 wxLogError( _T("Can't open clipboard.") );
292
293 return;
294 }
295
296 if ( !wxTheClipboard->IsSupported( wxDF_TEXT ) )
297 {
298 wxLogMessage( _T("No text on the clipboard") );
299 }
300 else
301 {
302 wxLogMessage( _T("There is text on the clipboard") );
303 }
304
305 wxTheClipboard->Close();
306 }
307
308 void DnDFrame::OnClipboardHasBitmap(wxCommandEvent& WXUNUSED(event))
309 {
310 if ( !wxTheClipboard->Open() )
311 {
312 wxLogError( _T("Can't open clipboard.") );
313
314 return;
315 }
316
317 if ( !wxTheClipboard->IsSupported( wxDF_BITMAP ) )
318 {
319 wxLogMessage( _T("No bitmap on the clipboard") );
320 }
321 else
322 {
323 wxLogMessage( _T("There is a bitmap on the clipboard") );
324 }
325
326 wxTheClipboard->Close();
327 }
328
329 void DnDFrame::OnDrag(wxCommandEvent& WXUNUSED(event))
330 {
331 wxString strText = wxGetTextFromUser
332 (
333 "After you enter text in this dialog, press any mouse\n"
334 "button in the bottom (empty) part of the frame and \n"
335 "drag it anywhere - you will be in fact dragging the\n"
336 "text object containing this text",
337 "Please enter some text", m_strText, this
338 );
339
340 m_strText = strText;
341 }
342
343 void DnDFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
344 {
345 wxMessageBox("Drag-&-Drop Demo\n"
346 "Please see \"Help|Help...\" for details\n"
347 "Copyright (c) 1998 Vadim Zeitlin",
348 "About wxDnD",
349 wxICON_INFORMATION | wxOK,
350 this);
351 }
352
353 void DnDFrame::OnHelp(wxCommandEvent& /* event */)
354 {
355 wxMessageDialog dialog(this,
356 "This small program demonstrates drag & drop support in wxWindows. The program window\n"
357 "consists of 3 parts: the bottom pane is for debug messages, so that you can see what's\n"
358 "going on inside. The top part is split into 2 listboxes, the left one accepts files\n"
359 "and the right one accepts text.\n"
360 "\n"
361 "To test wxDropTarget: open wordpad (write.exe), select some text in it and drag it to\n"
362 "the right listbox (you'll notice the usual visual feedback, i.e. the cursor will change).\n"
363 "Also, try dragging some files (you can select several at once) from Windows Explorer (or \n"
364 "File Manager) to the left pane. Hold down Ctrl/Shift keys when you drop text (doesn't \n"
365 "work with files) and see what changes.\n"
366 "\n"
367 "To test wxDropSource: just press any mouse button on the empty zone of the window and drag\n"
368 "it to wordpad or any other droptarget accepting text (and of course you can just drag it\n"
369 "to the right pane). Due to a lot of trace messages, the cursor might take some time to \n"
370 "change, don't release the mouse button until it does. You can change the string being\n"
371 "dragged in in \"File|Test drag...\" dialog.\n"
372 "\n"
373 "\n"
374 "Please send all questions/bug reports/suggestions &c to \n"
375 "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>",
376 "wxDnD Help");
377
378 dialog.ShowModal();
379 }
380
381 void DnDFrame::OnLogClear(wxCommandEvent& /* event */ )
382 {
383 m_ctrlLog->Clear();
384 }
385
386 void DnDFrame::OnLeftDown(wxMouseEvent &WXUNUSED(event) )
387 {
388 if ( !m_strText.IsEmpty() )
389 {
390 // start drag operation
391 #ifdef __WXMSW__
392 wxTextDataObject textData(m_strText);
393 wxDropSource dragSource( textData, this );
394 #else
395 wxDropSource dragSource( new wxTextDataObject (m_strText), this, wxIcon(mondrian_xpm) );
396 #endif
397 const char *pc;
398
399 switch ( dragSource.DoDragDrop(TRUE) )
400 {
401 case wxDragError: pc = "Error!"; break;
402 case wxDragNone: pc = "Nothing"; break;
403 case wxDragCopy: pc = "Copied"; break;
404 case wxDragMove: pc = "Moved"; break;
405 case wxDragCancel: pc = "Cancelled"; break;
406 default: pc = "Huh?"; break;
407 }
408
409 SetStatusText(wxString("Drag result: ") + pc);
410 }
411 }
412
413 void DnDFrame::OnRightDown(wxMouseEvent &event )
414 {
415 wxMenu *menu = new wxMenu;
416
417 menu->Append(Menu_Drag, "&Test drag...");
418 menu->Append(Menu_About, "&About");
419 menu->Append(Menu_Quit, "E&xit");
420
421 PopupMenu( menu, event.GetX(), event.GetY() );
422 }
423
424 DnDFrame::~DnDFrame()
425 {
426 if ( m_pLog != NULL ) {
427 if ( wxLog::SetActiveTarget(m_pLogPrev) == m_pLog )
428 delete m_pLog;
429 }
430 }
431
432 // ---------------------------------------------------------------------------
433 // bitmap clipboard
434 // ---------------------------------------------------------------------------
435
436 void DnDFrame::OnCopyBitmap(wxCommandEvent& WXUNUSED(event))
437 {
438 // PNG support is not always compiled in under Windows, so use BMP there
439 #ifdef __WXMSW__
440 wxFileDialog dialog(this, "Open a BMP file", "", "", "BMP files (*.bmp)|*.bmp", 0);
441 #else
442 wxFileDialog dialog(this, "Open a PNG file", "", "", "PNG files (*.png)|*.png", 0);
443 #endif
444
445 if (dialog.ShowModal() != wxID_OK)
446 {
447 wxLogMessage( _T("Aborted file open") );
448 return;
449 }
450
451 if (dialog.GetPath().IsEmpty())
452 {
453 wxLogMessage( _T("Returned empty string.") );
454 return;
455 }
456
457 if (!wxFileExists(dialog.GetPath()))
458 {
459 wxLogMessage( _T("File doesn't exist.") );
460 return;
461 }
462
463 wxImage image;
464 image.LoadFile( dialog.GetPath(),
465 #ifdef __WXMSW__
466 wxBITMAP_TYPE_BMP
467 #else
468 wxBITMAP_TYPE_PNG
469 #endif
470 );
471 if (!image.Ok())
472 {
473 wxLogMessage( _T("Invalid image file...") );
474 return;
475 }
476
477 wxLogMessage( _T("Decoding image file...") );
478 wxYield();
479
480 wxBitmap bitmap( image.ConvertToBitmap() );
481
482 if ( !wxTheClipboard->Open() )
483 {
484 wxLogError(_T("Can't open clipboard."));
485
486 return;
487 }
488
489 wxLogMessage( _T("Creating wxBitmapDataObject...") );
490 wxYield();
491
492 if ( !wxTheClipboard->AddData(new wxBitmapDataObject(bitmap)) )
493 {
494 wxLogError(_T("Can't copy image to the clipboard."));
495 }
496 else
497 {
498 wxLogMessage(_T("Image has been put on the clipboard.") );
499 wxLogMessage(_T("You can paste it now and look at it.") );
500 }
501
502 wxTheClipboard->Close();
503 }
504
505 void DnDFrame::OnPasteBitmap(wxCommandEvent& WXUNUSED(event))
506 {
507 if ( !wxTheClipboard->Open() )
508 {
509 wxLogError(_T("Can't open clipboard."));
510
511 return;
512 }
513
514 if ( !wxTheClipboard->IsSupported(wxDF_BITMAP) )
515 {
516 wxLogWarning(_T("No bitmap on clipboard"));
517
518 wxTheClipboard->Close();
519 return;
520 }
521
522 wxBitmapDataObject data;
523 if ( !wxTheClipboard->GetData(&data) )
524 {
525 wxLogError(_T("Can't paste bitmap from the clipboard"));
526 }
527 else
528 {
529 wxLogMessage(_T("Bitmap pasted from the clipboard") );
530 m_bitmap = data.GetBitmap();
531 Refresh();
532 }
533
534 wxTheClipboard->Close();
535 }
536
537 // ---------------------------------------------------------------------------
538 // text clipboard
539 // ---------------------------------------------------------------------------
540
541 void DnDFrame::OnCopy(wxCommandEvent& WXUNUSED(event))
542 {
543 if ( !wxTheClipboard->Open() )
544 {
545 wxLogError(_T("Can't open clipboard."));
546
547 return;
548 }
549
550 if ( !wxTheClipboard->AddData(new wxTextDataObject(m_strText)) )
551 {
552 wxLogError(_T("Can't copy data to the clipboard"));
553 }
554 else
555 {
556 wxLogMessage(_T("Text '%s' put on the clipboard"), m_strText.c_str());
557 }
558
559 wxTheClipboard->Close();
560 }
561
562 void DnDFrame::OnPaste(wxCommandEvent& WXUNUSED(event))
563 {
564 if ( !wxTheClipboard->Open() )
565 {
566 wxLogError(_T("Can't open clipboard."));
567
568 return;
569 }
570
571 if ( !wxTheClipboard->IsSupported(wxDF_TEXT) )
572 {
573 wxLogWarning(_T("No text data on clipboard"));
574
575 wxTheClipboard->Close();
576 return;
577 }
578
579 wxTextDataObject text;
580 if ( !wxTheClipboard->GetData(&text) )
581 {
582 wxLogError(_T("Can't paste data from the clipboard"));
583 }
584 else
585 {
586 wxLogMessage(_T("Text '%s' pasted from the clipboard"),
587 text.GetText().c_str());
588 }
589
590 wxTheClipboard->Close();
591 }
592
593 // ----------------------------------------------------------------------------
594 // Notifications called by the base class
595 // ----------------------------------------------------------------------------
596
597 bool DnDText::OnDropText( wxDropPointCoord, wxDropPointCoord, const wxChar *psz )
598 {
599 m_pOwner->Append(psz);
600
601 return TRUE;
602 }
603
604 bool DnDFile::OnDropFiles( wxDropPointCoord, wxDropPointCoord, size_t nFiles,
605 const wxChar* const aszFiles[])
606 {
607 wxString str;
608 str.Printf( _T("%d files dropped"), nFiles);
609 m_pOwner->Append(str);
610 for ( size_t n = 0; n < nFiles; n++ ) {
611 m_pOwner->Append(aszFiles[n]);
612 }
613
614 return TRUE;
615 }