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