dragimag.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: dragimag.cpp
  3. // Purpose: wxDragImage sample
  4. // Author: Julian Smart
  5. // Modified by:
  6. // Created: 28/2/2000
  7. // Copyright: (c) Julian Smart
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. // For compilers that support precompilation, includes "wx/wx.h".
  11. #include "wx/wxprec.h"
  12. #ifdef __BORLANDC__
  13. #pragma hdrstop
  14. #endif
  15. #ifndef WX_PRECOMP
  16. #include "wx/wx.h"
  17. #endif
  18. #include "wx/image.h"
  19. // Under Windows, change this to 1
  20. // to use wxGenericDragImage
  21. #define wxUSE_GENERIC_DRAGIMAGE 1
  22. #if wxUSE_GENERIC_DRAGIMAGE
  23. #include "wx/generic/dragimgg.h"
  24. #define wxDragImage wxGenericDragImage
  25. #else
  26. #include "wx/dragimag.h"
  27. #endif
  28. #include "dragimag.h"
  29. #ifndef wxHAS_IMAGES_IN_RESOURCES
  30. #include "../sample.xpm"
  31. #include "dragicon.xpm"
  32. #endif
  33. // main program
  34. IMPLEMENT_APP(MyApp)
  35. // MyCanvas
  36. IMPLEMENT_CLASS(MyCanvas, wxScrolledWindow)
  37. wxBEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
  38. EVT_PAINT(MyCanvas::OnPaint)
  39. EVT_ERASE_BACKGROUND(MyCanvas::OnEraseBackground)
  40. EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
  41. wxEND_EVENT_TABLE()
  42. MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id,
  43. const wxPoint &pos, const wxSize &size )
  44. : wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER )
  45. {
  46. SetBackgroundColour(* wxWHITE);
  47. SetCursor(wxCursor(wxCURSOR_ARROW));
  48. m_dragMode = TEST_DRAG_NONE;
  49. m_draggedShape = (DragShape*) NULL;
  50. m_dragImage = (wxDragImage*) NULL;
  51. m_currentlyHighlighted = (DragShape*) NULL;
  52. }
  53. MyCanvas::~MyCanvas()
  54. {
  55. ClearShapes();
  56. if (m_dragImage)
  57. delete m_dragImage;
  58. }
  59. void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
  60. {
  61. wxPaintDC dc( this );
  62. PrepareDC( dc );
  63. DrawShapes(dc);
  64. }
  65. void MyCanvas::OnEraseBackground(wxEraseEvent& event)
  66. {
  67. if (wxGetApp().GetBackgroundBitmap().IsOk())
  68. {
  69. wxSize sz = GetClientSize();
  70. wxRect rect(0, 0, sz.x, sz.y);
  71. if (event.GetDC())
  72. {
  73. wxGetApp().TileBitmap(rect, *(event.GetDC()), wxGetApp().GetBackgroundBitmap());
  74. }
  75. else
  76. {
  77. wxClientDC dc(this);
  78. wxGetApp().TileBitmap(rect, dc, wxGetApp().GetBackgroundBitmap());
  79. }
  80. }
  81. else
  82. event.Skip(); // The official way of doing it
  83. }
  84. void MyCanvas::OnMouseEvent(wxMouseEvent& event)
  85. {
  86. if (event.LeftDown())
  87. {
  88. DragShape* shape = FindShape(event.GetPosition());
  89. if (shape)
  90. {
  91. // We tentatively start dragging, but wait for
  92. // mouse movement before dragging properly.
  93. m_dragMode = TEST_DRAG_START;
  94. m_dragStartPos = event.GetPosition();
  95. m_draggedShape = shape;
  96. }
  97. }
  98. else if (event.LeftUp() && m_dragMode != TEST_DRAG_NONE)
  99. {
  100. // Finish dragging
  101. m_dragMode = TEST_DRAG_NONE;
  102. if (!m_draggedShape || !m_dragImage)
  103. return;
  104. m_draggedShape->SetPosition(m_draggedShape->GetPosition()
  105. + event.GetPosition() - m_dragStartPos);
  106. m_dragImage->Hide();
  107. m_dragImage->EndDrag();
  108. wxDELETE(m_dragImage);
  109. m_draggedShape->SetShow(true);
  110. m_currentlyHighlighted = (DragShape*) NULL;
  111. m_draggedShape = (DragShape*) NULL;
  112. Refresh(true);
  113. }
  114. else if (event.Dragging() && m_dragMode != TEST_DRAG_NONE)
  115. {
  116. if (m_dragMode == TEST_DRAG_START)
  117. {
  118. // We will start dragging if we've moved beyond a couple of pixels
  119. int tolerance = 2;
  120. int dx = abs(event.GetPosition().x - m_dragStartPos.x);
  121. int dy = abs(event.GetPosition().y - m_dragStartPos.y);
  122. if (dx <= tolerance && dy <= tolerance)
  123. return;
  124. // Start the drag.
  125. m_dragMode = TEST_DRAG_DRAGGING;
  126. if (m_dragImage)
  127. delete m_dragImage;
  128. // Erase the dragged shape from the canvas
  129. m_draggedShape->SetShow(false);
  130. // redraw immediately
  131. Refresh(true);
  132. Update();
  133. switch (m_draggedShape->GetDragMethod())
  134. {
  135. case SHAPE_DRAG_BITMAP:
  136. {
  137. m_dragImage = new MyDragImage(this, m_draggedShape->GetBitmap(), wxCursor(wxCURSOR_HAND));
  138. break;
  139. }
  140. case SHAPE_DRAG_TEXT:
  141. {
  142. m_dragImage = new MyDragImage(this, wxString(wxT("Dragging some test text")), wxCursor(wxCURSOR_HAND));
  143. break;
  144. }
  145. case SHAPE_DRAG_ICON:
  146. {
  147. m_dragImage = new MyDragImage(this, wxICON(dragicon), wxCursor(wxCURSOR_HAND));
  148. break;
  149. }
  150. }
  151. bool fullScreen = wxGetApp().GetUseScreen();
  152. // The offset between the top-left of the shape image and the current shape position
  153. wxPoint beginDragHotSpot = m_dragStartPos - m_draggedShape->GetPosition();
  154. // Now we do this inside the implementation: always assume
  155. // coordinates relative to the capture window (client coordinates)
  156. //if (fullScreen)
  157. // beginDragHotSpot -= ClientToScreen(wxPoint(0, 0));
  158. if (!m_dragImage->BeginDrag(beginDragHotSpot, this, fullScreen))
  159. {
  160. wxDELETE(m_dragImage);
  161. m_dragMode = TEST_DRAG_NONE;
  162. } else
  163. {
  164. m_dragImage->Move(event.GetPosition());
  165. m_dragImage->Show();
  166. }
  167. }
  168. else if (m_dragMode == TEST_DRAG_DRAGGING)
  169. {
  170. // We're currently dragging. See if we're over another shape.
  171. DragShape* onShape = FindShape(event.GetPosition());
  172. bool mustUnhighlightOld = false;
  173. bool mustHighlightNew = false;
  174. if (m_currentlyHighlighted)
  175. {
  176. if ((onShape == (DragShape*) NULL) || (m_currentlyHighlighted != onShape))
  177. mustUnhighlightOld = true;
  178. }
  179. if (onShape && (onShape != m_currentlyHighlighted) && onShape->IsShown())
  180. mustHighlightNew = true;
  181. if (mustUnhighlightOld || mustHighlightNew)
  182. m_dragImage->Hide();
  183. // Now with the drag image switched off, we can change the window contents.
  184. if (mustUnhighlightOld)
  185. m_currentlyHighlighted = (DragShape*) NULL;
  186. if (mustHighlightNew)
  187. m_currentlyHighlighted = onShape;
  188. if (mustUnhighlightOld || mustHighlightNew)
  189. {
  190. Refresh(mustUnhighlightOld);
  191. Update();
  192. }
  193. // Move and show the image again
  194. m_dragImage->Move(event.GetPosition());
  195. if (mustUnhighlightOld || mustHighlightNew)
  196. m_dragImage->Show();
  197. }
  198. }
  199. }
  200. void MyCanvas::DrawShapes(wxDC& dc)
  201. {
  202. wxList::compatibility_iterator node = m_displayList.GetFirst();
  203. while (node)
  204. {
  205. DragShape* shape = (DragShape*) node->GetData();
  206. if (shape->IsShown() && m_draggedShape != shape)
  207. {
  208. shape->Draw(dc, (m_currentlyHighlighted == shape));
  209. }
  210. node = node->GetNext();
  211. }
  212. }
  213. void MyCanvas::EraseShape(DragShape* shape, wxDC& dc)
  214. {
  215. wxSize sz = GetClientSize();
  216. wxRect rect(0, 0, sz.x, sz.y);
  217. wxRect rect2(shape->GetRect());
  218. dc.SetClippingRegion(rect2.x, rect2.y, rect2.width, rect2.height);
  219. wxGetApp().TileBitmap(rect, dc, wxGetApp().GetBackgroundBitmap());
  220. dc.DestroyClippingRegion();
  221. }
  222. void MyCanvas::ClearShapes()
  223. {
  224. wxList::compatibility_iterator node = m_displayList.GetFirst();
  225. while (node)
  226. {
  227. DragShape* shape = (DragShape*) node->GetData();
  228. delete shape;
  229. node = node->GetNext();
  230. }
  231. m_displayList.Clear();
  232. }
  233. DragShape* MyCanvas::FindShape(const wxPoint& pt) const
  234. {
  235. wxList::compatibility_iterator node = m_displayList.GetFirst();
  236. while (node)
  237. {
  238. DragShape* shape = (DragShape*) node->GetData();
  239. if (shape->HitTest(pt))
  240. return shape;
  241. node = node->GetNext();
  242. }
  243. return (DragShape*) NULL;
  244. }
  245. // MyFrame
  246. IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
  247. wxBEGIN_EVENT_TABLE(MyFrame,wxFrame)
  248. EVT_MENU (wxID_ABOUT, MyFrame::OnAbout)
  249. EVT_MENU (wxID_EXIT, MyFrame::OnQuit)
  250. wxEND_EVENT_TABLE()
  251. MyFrame::MyFrame()
  252. : wxFrame( (wxFrame *)NULL, wxID_ANY, wxT("wxDragImage sample"),
  253. wxPoint(20,20), wxSize(470,360) )
  254. {
  255. wxMenu *file_menu = new wxMenu();
  256. file_menu->Append( wxID_ABOUT, wxT("&About"));
  257. file_menu->AppendCheckItem( TEST_USE_SCREEN, wxT("&Use whole screen for dragging"), wxT("Use whole screen"));
  258. file_menu->Append( wxID_EXIT, wxT("E&xit"));
  259. wxMenuBar *menu_bar = new wxMenuBar();
  260. menu_bar->Append(file_menu, wxT("&File"));
  261. SetIcon(wxICON(sample));
  262. SetMenuBar( menu_bar );
  263. #if wxUSE_STATUSBAR
  264. CreateStatusBar(2);
  265. int widths[] = { -1, 100 };
  266. SetStatusWidths( 2, widths );
  267. #endif // wxUSE_STATUSBAR
  268. m_canvas = new MyCanvas( this, wxID_ANY, wxPoint(0,0), wxSize(10,10) );
  269. }
  270. void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )
  271. {
  272. Close( true );
  273. }
  274. void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) )
  275. {
  276. (void)wxMessageBox( wxT("wxDragImage demo\n")
  277. wxT("Julian Smart (c) 2000"),
  278. wxT("About wxDragImage Demo"),
  279. wxICON_INFORMATION | wxOK );
  280. }
  281. //-----------------------------------------------------------------------------
  282. // MyApp
  283. //-----------------------------------------------------------------------------
  284. wxBEGIN_EVENT_TABLE(MyApp, wxApp)
  285. EVT_MENU(TEST_USE_SCREEN, MyApp::OnUseScreen)
  286. wxEND_EVENT_TABLE()
  287. MyApp::MyApp()
  288. {
  289. // Drag across whole screen
  290. m_useScreen = false;
  291. }
  292. bool MyApp::OnInit()
  293. {
  294. if ( !wxApp::OnInit() )
  295. return false;
  296. #if wxUSE_LIBPNG
  297. wxImage::AddHandler( new wxPNGHandler );
  298. #endif
  299. wxImage image;
  300. if (image.LoadFile(wxT("backgrnd.png"), wxBITMAP_TYPE_PNG))
  301. {
  302. m_background = wxBitmap(image);
  303. }
  304. MyFrame *frame = new MyFrame();
  305. wxString rootName(wxT("shape0"));
  306. for (int i = 1; i < 4; i++)
  307. {
  308. /* For some reason under wxX11, the 2nd LoadFile in this loop fails, with
  309. a BadMatch inside CreateFromImage (inside ConvertToBitmap). This happens even if you copy
  310. the first file over the second file. */
  311. if (image.LoadFile(wxString::Format("%s%d.png", rootName, i), wxBITMAP_TYPE_PNG))
  312. {
  313. DragShape* newShape = new DragShape(wxBitmap(image));
  314. newShape->SetPosition(wxPoint(i*50, i*50));
  315. if (i == 2)
  316. newShape->SetDragMethod(SHAPE_DRAG_TEXT);
  317. else if (i == 3)
  318. newShape->SetDragMethod(SHAPE_DRAG_ICON);
  319. else
  320. newShape->SetDragMethod(SHAPE_DRAG_BITMAP);
  321. frame->GetCanvas()->GetDisplayList().Append(newShape);
  322. }
  323. }
  324. #if 0
  325. // Under Motif or GTK, this demonstrates that
  326. // wxScreenDC only gets the root window content.
  327. // We need to be able to copy the overall content
  328. // for full-screen dragging to work.
  329. int w, h;
  330. wxDisplaySize(& w, & h);
  331. wxBitmap bitmap(w, h);
  332. wxScreenDC dc;
  333. wxMemoryDC memDC;
  334. memDC.SelectObject(bitmap);
  335. memDC.Blit(0, 0, w, h, & dc, 0, 0);
  336. memDC.SelectObject(wxNullBitmap);
  337. m_background = bitmap;
  338. #endif
  339. frame->Show( true );
  340. return true;
  341. }
  342. int MyApp::OnExit()
  343. {
  344. return 0;
  345. }
  346. bool MyApp::TileBitmap(const wxRect& rect, wxDC& dc, wxBitmap& bitmap)
  347. {
  348. int w = bitmap.GetWidth();
  349. int h = bitmap.GetHeight();
  350. int i, j;
  351. for (i = rect.x; i < rect.x + rect.width; i += w)
  352. {
  353. for (j = rect.y; j < rect.y + rect.height; j+= h)
  354. dc.DrawBitmap(bitmap, i, j);
  355. }
  356. return true;
  357. }
  358. void MyApp::OnUseScreen(wxCommandEvent& WXUNUSED(event))
  359. {
  360. m_useScreen = !m_useScreen;
  361. }
  362. // DragShape
  363. DragShape::DragShape(const wxBitmap& bitmap)
  364. {
  365. m_bitmap = bitmap;
  366. m_pos.x = 0;
  367. m_pos.y = 0;
  368. m_dragMethod = SHAPE_DRAG_BITMAP;
  369. m_show = true;
  370. }
  371. bool DragShape::HitTest(const wxPoint& pt) const
  372. {
  373. wxRect rect(GetRect());
  374. return rect.Contains(pt.x, pt.y);
  375. }
  376. bool DragShape::Draw(wxDC& dc, bool highlight)
  377. {
  378. if (m_bitmap.IsOk())
  379. {
  380. wxMemoryDC memDC;
  381. memDC.SelectObject(m_bitmap);
  382. dc.Blit(m_pos.x, m_pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight(),
  383. & memDC, 0, 0, wxCOPY, true);
  384. if (highlight)
  385. {
  386. dc.SetPen(*wxWHITE_PEN);
  387. dc.SetBrush(*wxTRANSPARENT_BRUSH);
  388. dc.DrawRectangle(m_pos.x, m_pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight());
  389. }
  390. return true;
  391. }
  392. else
  393. return false;
  394. }
  395. // MyDragImage
  396. // On some platforms, notably Mac OS X with Core Graphics, we can't blit from
  397. // a window, so we need to draw the background explicitly.
  398. bool MyDragImage::UpdateBackingFromWindow(wxDC& WXUNUSED(windowDC), wxMemoryDC& destDC, const wxRect& WXUNUSED(sourceRect),
  399. const wxRect& destRect) const
  400. {
  401. destDC.SetClippingRegion(destRect);
  402. if (wxGetApp().GetBackgroundBitmap().IsOk())
  403. wxGetApp().TileBitmap(destRect, destDC, wxGetApp().GetBackgroundBitmap());
  404. m_canvas->DrawShapes(destDC);
  405. return true;
  406. }