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