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