home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / generic / dragimgg.cpp < prev    next >
C/C++ Source or Header  |  2002-10-08  |  15KB  |  513 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        dragimgg.cpp
  3. // Purpose:     Generic wxDragImage implementation
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     29/2/2000
  7. // RCS-ID:      $Id: dragimgg.cpp,v 1.9.2.1 2002/10/02 08:11:27 JS Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:     wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #ifdef __GNUG__
  21. #pragma implementation "dragimgg.h"
  22. #endif
  23.  
  24. // For compilers that support precompilation, includes "wx.h".
  25. #include "wx/wxprec.h"
  26.  
  27. #ifdef __BORLANDC__
  28. #pragma hdrstop
  29. #endif
  30.  
  31. #if wxUSE_DRAGIMAGE
  32.  
  33. #ifndef WX_PRECOMP
  34. #include <stdio.h>
  35. #include "wx/setup.h"
  36. #include "wx/window.h"
  37. #include "wx/frame.h"
  38. #include "wx/dcclient.h"
  39. #include "wx/dcscreen.h"
  40. #include "wx/dcmemory.h"
  41. #include "wx/settings.h"
  42. #endif
  43.  
  44. #include "wx/log.h"
  45. #include "wx/intl.h"
  46.  
  47. #ifdef __WIN16__
  48. #define wxUSE_IMAGE_IN_DRAGIMAGE 0
  49. #else
  50. #define wxUSE_IMAGE_IN_DRAGIMAGE 1
  51. #endif
  52.  
  53. #if wxUSE_IMAGE_IN_DRAGIMAGE
  54. #include "wx/image.h"
  55. #endif
  56.  
  57. #include "wx/generic/dragimgg.h"
  58.  
  59. // ----------------------------------------------------------------------------
  60. // macros
  61. // ----------------------------------------------------------------------------
  62.  
  63. IMPLEMENT_DYNAMIC_CLASS(wxGenericDragImage, wxObject)
  64.  
  65. // ============================================================================
  66. // implementation
  67. // ============================================================================
  68.  
  69. // ----------------------------------------------------------------------------
  70. // wxGenericDragImage ctors/dtor
  71. // ----------------------------------------------------------------------------
  72.  
  73. wxGenericDragImage::~wxGenericDragImage()
  74. {
  75.     if (m_windowDC)
  76.     {
  77.         delete m_windowDC;
  78.     }
  79. }
  80.  
  81. void wxGenericDragImage::Init()
  82. {
  83.     m_isDirty = FALSE;
  84.     m_isShown = FALSE;
  85.     m_windowDC = (wxDC*) NULL;
  86.     m_window = (wxWindow*) NULL;
  87.     m_fullScreen = FALSE;
  88.     m_pBackingBitmap = (wxBitmap*) NULL;
  89. }
  90.  
  91. // Attributes
  92. ////////////////////////////////////////////////////////////////////////////
  93.  
  94.  
  95. // Operations
  96. ////////////////////////////////////////////////////////////////////////////
  97.  
  98. // Create a drag image with a virtual image (need to override DoDrawImage, GetImageRect)
  99. bool wxGenericDragImage::Create(const wxCursor& cursor)
  100. {
  101.     m_cursor = cursor;
  102.  
  103.     return TRUE;
  104. }
  105.  
  106. // Create a drag image from a bitmap and optional cursor
  107. bool wxGenericDragImage::Create(const wxBitmap& image, const wxCursor& cursor)
  108. {
  109.     // We don't have to combine the cursor explicitly since we simply show the cursor
  110.     // as we drag. This currently will only work within one window.
  111.  
  112.     m_cursor = cursor;
  113.     m_bitmap = image;
  114.  
  115.     return TRUE ;
  116. }
  117.  
  118. // Create a drag image from an icon and optional cursor
  119. bool wxGenericDragImage::Create(const wxIcon& image, const wxCursor& cursor)
  120. {
  121.     // We don't have to combine the cursor explicitly since we simply show the cursor
  122.     // as we drag. This currently will only work within one window.
  123.  
  124.     m_cursor = cursor;
  125.     m_icon = image;
  126.  
  127.     return TRUE ;
  128. }
  129.  
  130. // Create a drag image from a string and optional cursor
  131. bool wxGenericDragImage::Create(const wxString& str, const wxCursor& cursor)
  132. {
  133.     wxFont font(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
  134.  
  135.     long w, h;
  136.     wxScreenDC dc;
  137.     dc.SetFont(font);
  138.     dc.GetTextExtent(str, & w, & h);
  139.     dc.SetFont(wxNullFont);
  140.  
  141.     wxMemoryDC dc2;
  142.  
  143.     // Sometimes GetTextExtent isn't accurate enough, so make it longer
  144.     wxBitmap bitmap((int) ((w+2) * 1.5), (int) h+2);
  145.     dc2.SelectObject(bitmap);
  146.  
  147.     dc2.SetFont(font);
  148.     dc2.SetBackground(* wxWHITE_BRUSH);
  149.     dc2.Clear();
  150.     dc2.SetBackgroundMode(wxTRANSPARENT);
  151.     dc2.SetTextForeground(* wxLIGHT_GREY);
  152.     dc2.DrawText(str, 0, 0);
  153.     dc2.DrawText(str, 1, 0);
  154.     dc2.DrawText(str, 2, 0);
  155.     dc2.DrawText(str, 1, 1);
  156.     dc2.DrawText(str, 2, 1);
  157.     dc2.DrawText(str, 1, 2);
  158.     dc2.DrawText(str, 2, 2);
  159.  
  160.     dc2.SetTextForeground(* wxBLACK);
  161.     dc2.DrawText(str, 1, 1);
  162.  
  163.     dc2.SelectObject(wxNullBitmap);
  164.  
  165. #if wxUSE_IMAGE_IN_DRAGIMAGE
  166.     // Make the bitmap masked
  167.     wxImage image = bitmap.ConvertToImage();
  168.     image.SetMaskColour(255, 255, 255);
  169.     bitmap = wxBitmap(image);
  170. #endif
  171.  
  172.     return Create(bitmap, cursor);
  173. }
  174.  
  175. // Create a drag image for the given tree control item
  176. bool wxGenericDragImage::Create(const wxTreeCtrl& treeCtrl, wxTreeItemId& id)
  177. {
  178.     wxString str = treeCtrl.GetItemText(id);
  179.     return Create(str);
  180. }
  181.  
  182. // Create a drag image for the given list control item
  183. bool wxGenericDragImage::Create(const wxListCtrl& listCtrl, long id)
  184. {
  185.     wxString str = listCtrl.GetItemText(id);
  186.     return Create(str);
  187. }
  188.  
  189. // Begin drag
  190. bool wxGenericDragImage::BeginDrag(const wxPoint& hotspot,
  191.                                    wxWindow* window,
  192.                                    bool fullScreen,
  193.                                    wxRect* rect)
  194. {
  195.     wxASSERT_MSG( (window != 0), wxT("Window must not be null in BeginDrag."));
  196.  
  197.     // The image should be offset by this amount
  198.     m_offset = hotspot;
  199.     m_window = window;
  200.     m_fullScreen = fullScreen;
  201.  
  202.     if (rect)
  203.         m_boundingRect = * rect;
  204.  
  205.     m_isDirty = FALSE;
  206.     m_isDirty = FALSE;
  207.  
  208.     if (window)
  209.     {
  210.         window->CaptureMouse();
  211.  
  212.         if (m_cursor.Ok())
  213.         {
  214.             m_oldCursor = window->GetCursor();
  215.             window->SetCursor(m_cursor);
  216.         }
  217.     }
  218.  
  219.     // Make a copy of the window so we can repair damage done as the image is
  220.     // dragged.
  221.  
  222.     wxSize clientSize;
  223.     wxPoint pt(0, 0);
  224.     if (!m_fullScreen)
  225.     {
  226.         clientSize = window->GetClientSize();
  227.         m_boundingRect.x = 0; m_boundingRect.y = 0;
  228.         m_boundingRect.width = clientSize.x; m_boundingRect.height = clientSize.y;
  229.     }
  230.     else
  231.     {
  232.         int w, h;
  233.         wxDisplaySize(& w, & h);
  234.         clientSize.x = w; clientSize.y = h;
  235.         if (rect)
  236.         {
  237.             pt.x = m_boundingRect.x; pt.y = m_boundingRect.y;
  238.             clientSize.x = m_boundingRect.width; clientSize.y = m_boundingRect.height;
  239.         }
  240.         else
  241.         {
  242.             m_boundingRect.x = 0; m_boundingRect.y = 0;
  243.             m_boundingRect.width = w; m_boundingRect.height = h;
  244.         }
  245.     }
  246.  
  247.     wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap);
  248.  
  249.     if (!backing->Ok() || (backing->GetWidth() < clientSize.x || backing->GetHeight() < clientSize.y))
  250.         (*backing) = wxBitmap(clientSize.x, clientSize.y);
  251.  
  252.     if (!m_fullScreen)
  253.     {
  254.         m_windowDC = new wxClientDC(window);
  255.     }
  256.     else
  257.     {
  258.         m_windowDC = new wxScreenDC;
  259.  
  260. #if 0
  261.         // Use m_boundingRect to limit the area considered.
  262.         ((wxScreenDC*) m_windowDC)->StartDrawingOnTop(rect);
  263. #endif
  264.  
  265.         m_windowDC->SetClippingRegion(m_boundingRect.x, m_boundingRect.y,
  266.             m_boundingRect.width, m_boundingRect.height);
  267.     }
  268.  
  269.     return TRUE;
  270. }
  271.  
  272. // Begin drag. hotspot is the location of the drag position relative to the upper-left
  273. // corner of the image. This is full screen only. fullScreenRect gives the
  274. // position of the window on the screen, to restrict the drag to.
  275. bool wxGenericDragImage::BeginDrag(const wxPoint& hotspot, wxWindow* window, wxWindow* fullScreenRect)
  276. {
  277.     wxRect rect;
  278.  
  279.     int x = fullScreenRect->GetPosition().x;
  280.     int y = fullScreenRect->GetPosition().y;
  281.     
  282.     wxSize sz = fullScreenRect->GetSize();
  283.  
  284.     if (fullScreenRect->GetParent() && !fullScreenRect->IsKindOf(CLASSINFO(wxFrame)))
  285.         fullScreenRect->GetParent()->ClientToScreen(& x, & y);
  286.  
  287.     rect.x = x; rect.y = y;
  288.     rect.width = sz.x; rect.height = sz.y;
  289.  
  290.     return BeginDrag(hotspot, window, TRUE, & rect);
  291. }
  292.  
  293. // End drag
  294. bool wxGenericDragImage::EndDrag()
  295. {
  296.     if (m_window)
  297.     {
  298. #ifdef __WXMSW__
  299.         // Under Windows we can be pretty sure this test will give
  300.         // the correct results
  301.         if (wxWindow::GetCapture() == m_window)
  302. #endif
  303.             m_window->ReleaseMouse();
  304.  
  305.         if (m_cursor.Ok() && m_oldCursor.Ok())
  306.         {
  307.             m_window->SetCursor(m_oldCursor);
  308.         }
  309.     }
  310.  
  311.     if (m_windowDC)
  312.     {
  313.         m_windowDC->DestroyClippingRegion();
  314.         delete m_windowDC;
  315.         m_windowDC = (wxDC*) NULL;
  316.     }
  317.  
  318.     m_repairBitmap = wxNullBitmap;
  319.  
  320.     return TRUE;
  321. }
  322.  
  323. // Move the image: call from OnMouseMove. Pt is in window client coordinates if window
  324. // is non-NULL, or in screen coordinates if NULL.
  325. bool wxGenericDragImage::Move(const wxPoint& pt)
  326. {
  327.     wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), wxT("No window DC in wxGenericDragImage::Move()") );
  328.  
  329.     wxPoint pt2(pt);
  330.     if (m_fullScreen)
  331.         pt2 = m_window->ClientToScreen(pt);
  332.  
  333.     // Erase at old position, then show at the current position
  334.     wxPoint oldPos = m_position;
  335.  
  336.     bool eraseOldImage = (m_isDirty && m_isShown);
  337.     
  338.     if (m_isShown)
  339.         RedrawImage(oldPos - m_offset, pt2 - m_offset, eraseOldImage, TRUE);
  340.  
  341.     m_position = pt2;
  342.  
  343.     if (m_isShown)
  344.         m_isDirty = TRUE;
  345.  
  346.     return TRUE;
  347. }
  348.  
  349. bool wxGenericDragImage::Show()
  350. {
  351.     wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), wxT("No window DC in wxGenericDragImage::Show()") );
  352.     
  353.     // Show at the current position
  354.  
  355.     if (!m_isShown)
  356.     {
  357.         // This is where we restore the backing bitmap, in case
  358.         // something has changed on the window.
  359.  
  360.         wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap);
  361.         wxMemoryDC memDC;
  362.         memDC.SelectObject(* backing);
  363.  
  364.         UpdateBackingFromWindow(* m_windowDC, memDC, m_boundingRect, wxRect(0, 0, m_boundingRect.width, m_boundingRect.height));
  365.  
  366.         //memDC.Blit(0, 0, m_boundingRect.width, m_boundingRect.height, m_windowDC, m_boundingRect.x, m_boundingRect.y);
  367.         memDC.SelectObject(wxNullBitmap);
  368.  
  369.         RedrawImage(m_position - m_offset, m_position - m_offset, FALSE, TRUE);
  370.     }
  371.  
  372.     m_isShown = TRUE;
  373.     m_isDirty = TRUE;
  374.  
  375.     return TRUE;
  376. }
  377.  
  378. bool wxGenericDragImage::UpdateBackingFromWindow(wxDC& windowDC, wxMemoryDC& destDC,
  379.     const wxRect& sourceRect, const wxRect& destRect) const
  380. {
  381.     return destDC.Blit(destRect.x, destRect.y, destRect.width, destRect.height, & windowDC,
  382.         sourceRect.x, sourceRect.y);
  383. }
  384.  
  385. bool wxGenericDragImage::Hide()
  386. {
  387.     wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), wxT("No window DC in wxGenericDragImage::Hide()") );
  388.  
  389.     // Repair the old position
  390.  
  391.     if (m_isShown && m_isDirty)
  392.     {
  393.         RedrawImage(m_position - m_offset, m_position - m_offset, TRUE, FALSE);
  394.     }
  395.  
  396.     m_isShown = FALSE;
  397.     m_isDirty = FALSE;
  398.  
  399.     return TRUE;
  400. }
  401.  
  402. // More efficient: erase and redraw simultaneously if possible
  403. bool wxGenericDragImage::RedrawImage(const wxPoint& oldPos, const wxPoint& newPos,
  404.                                      bool eraseOld, bool drawNew)
  405. {
  406.     if (!m_windowDC)
  407.         return FALSE;
  408.  
  409.     wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap);
  410.     if (!backing->Ok())
  411.         return FALSE;
  412.  
  413.     wxRect oldRect(GetImageRect(oldPos));
  414.     wxRect newRect(GetImageRect(newPos));
  415.  
  416.     wxRect fullRect;
  417.  
  418.     // Full rect: the combination of both rects
  419.     if (eraseOld && drawNew)
  420.     {
  421.         int oldRight = oldRect.GetRight();
  422.         int oldBottom = oldRect.GetBottom();
  423.         int newRight = newRect.GetRight();
  424.         int newBottom = newRect.GetBottom();
  425.  
  426.         wxPoint topLeft = wxPoint(wxMin(oldPos.x, newPos.x), wxMin(oldPos.y, newPos.y));
  427.         wxPoint bottomRight = wxPoint(wxMax(oldRight, newRight), wxMax(oldBottom, newBottom));
  428.  
  429.         fullRect.x = topLeft.x; fullRect.y = topLeft.y;
  430.         fullRect.SetRight(bottomRight.x);
  431.         fullRect.SetBottom(bottomRight.y);
  432.     }
  433.     else if (eraseOld)
  434.         fullRect = oldRect;
  435.     else if (drawNew)
  436.         fullRect = newRect;
  437.  
  438.     // Make the bitmap bigger than it need be, so we don't
  439.     // keep reallocating all the time.
  440.     int excess = 50;
  441.  
  442.     if (!m_repairBitmap.Ok() || (m_repairBitmap.GetWidth() < fullRect.GetWidth() || m_repairBitmap.GetHeight() < fullRect.GetHeight()))
  443.     {
  444.         m_repairBitmap = wxBitmap(fullRect.GetWidth() + excess, fullRect.GetHeight() + excess);
  445.     }
  446.  
  447.     wxMemoryDC memDC;
  448.     memDC.SelectObject(* backing);
  449.  
  450.     wxMemoryDC memDCTemp;
  451.     memDCTemp.SelectObject(m_repairBitmap);
  452.  
  453.     // Draw the backing bitmap onto the repair bitmap.
  454.     // If full-screen, we may have specified the rect on the
  455.     // screen that we're using for our backing bitmap.
  456.     // So subtract this when we're blitting from the backing bitmap
  457.     // (translate from screen to backing-bitmap coords).
  458.  
  459.     memDCTemp.Blit(0, 0, fullRect.GetWidth(), fullRect.GetHeight(), & memDC, fullRect.x - m_boundingRect.x, fullRect.y - m_boundingRect.y);
  460.  
  461.     // If drawing, draw the image onto the mem DC
  462.     if (drawNew)
  463.     {
  464.         wxPoint pos(newPos.x - fullRect.x, newPos.y - fullRect.y) ;
  465.         DoDrawImage(memDCTemp, pos);
  466.     }
  467.  
  468.     // Now blit to the window
  469.     // Finally, blit the temp mem DC to the window.
  470.     m_windowDC->Blit(fullRect.x, fullRect.y, fullRect.width, fullRect.height, & memDCTemp, 0, 0);
  471.  
  472.     memDCTemp.SelectObject(wxNullBitmap);
  473.     memDC.SelectObject(wxNullBitmap);
  474.  
  475.     return TRUE;
  476. }
  477.  
  478. // Override this if you are using a virtual image (drawing your own image)
  479. bool wxGenericDragImage::DoDrawImage(wxDC& dc, const wxPoint& pos) const
  480. {
  481.     if (m_bitmap.Ok())
  482.     {
  483.         dc.DrawBitmap(m_bitmap, pos.x, pos.y, (m_bitmap.GetMask() != 0));
  484.         return TRUE;
  485.     }
  486.     else if (m_icon.Ok())
  487.     {
  488.         dc.DrawIcon(m_icon, pos.x, pos.y);
  489.         return TRUE;
  490.     }
  491.     else
  492.         return FALSE;
  493. }
  494.  
  495. // Override this if you are using a virtual image (drawing your own image)
  496. wxRect wxGenericDragImage::GetImageRect(const wxPoint& pos) const
  497. {
  498.     if (m_bitmap.Ok())
  499.     {
  500.         return wxRect(pos.x, pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight());
  501.     }
  502.     else if (m_icon.Ok())
  503.     {
  504.         return wxRect(pos.x, pos.y, m_icon.GetWidth(), m_icon.GetHeight());
  505.     }
  506.     else
  507.     {
  508.         return wxRect(pos.x, pos.y, 0, 0);
  509.     }
  510. }
  511.  
  512. #endif // wxUSE_DRAGIMAGE
  513.