]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/dragimgg.cpp
Compilation fix for wxMSW build without PCH.
[wxWidgets.git] / src / generic / dragimgg.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/generic/dragimgg.cpp
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
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#if wxUSE_DRAGIMAGE
28
29#ifndef WX_PRECOMP
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"
38 #include "wx/log.h"
39 #include "wx/image.h"
40#endif
41
42#define wxUSE_IMAGE_IN_DRAGIMAGE 1
43
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
60wxGenericDragImage::~wxGenericDragImage()
61{
62 if (m_windowDC)
63 {
64 delete m_windowDC;
65 }
66}
67
68void wxGenericDragImage::Init()
69{
70 m_isDirty = false;
71 m_isShown = false;
72 m_windowDC = NULL;
73 m_window = NULL;
74 m_fullScreen = false;
75#ifdef wxHAS_NATIVE_OVERLAY
76 m_dcOverlay = NULL;
77#else
78 m_pBackingBitmap = NULL;
79#endif
80}
81
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
131// Attributes
132////////////////////////////////////////////////////////////////////////////
133
134
135// Operations
136////////////////////////////////////////////////////////////////////////////
137
138// Create a drag image with a virtual image (need to override DoDrawImage, GetImageRect)
139bool wxGenericDragImage::Create(const wxCursor& cursor)
140{
141 m_cursor = cursor;
142
143 return true;
144}
145
146// Create a drag image from a bitmap and optional cursor
147bool wxGenericDragImage::Create(const wxBitmap& image, const wxCursor& cursor)
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;
153 m_bitmap = image;
154
155 return true ;
156}
157
158// Create a drag image from an icon and optional cursor
159bool wxGenericDragImage::Create(const wxIcon& image, const wxCursor& cursor)
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;
165 m_icon = image;
166
167 return true ;
168}
169
170// Create a drag image from a string and optional cursor
171bool wxGenericDragImage::Create(const wxString& str, const wxCursor& cursor)
172{
173 wxFont font(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
174
175 wxCoord w = 0, h = 0;
176 wxScreenDC dc;
177 dc.SetFont(font);
178 dc.GetTextExtent(str, & w, & h);
179 dc.SetFont(wxNullFont);
180
181 wxMemoryDC dc2;
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
187 dc2.SetFont(font);
188 dc2.SetBackground(* wxWHITE_BRUSH);
189 dc2.Clear();
190 dc2.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
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
205#if wxUSE_IMAGE_IN_DRAGIMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB)
206 // Make the bitmap masked
207 wxImage image = bitmap.ConvertToImage();
208 image.SetMaskColour(255, 255, 255);
209 bitmap = wxBitmap(image);
210#endif
211
212 return Create(bitmap, cursor);
213}
214
215#if wxUSE_TREECTRL
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}
222#endif
223
224#if wxUSE_LISTCTRL
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}
231#endif
232
233// Begin drag
234bool wxGenericDragImage::BeginDrag(const wxPoint& hotspot,
235 wxWindow* window,
236 bool fullScreen,
237 wxRect* rect)
238{
239 wxCHECK_MSG( window, false, wxT("Window must not be null in BeginDrag."));
240
241 // The image should be offset by this amount
242 m_offset = hotspot;
243 m_window = window;
244 m_fullScreen = fullScreen;
245
246 if (rect)
247 m_boundingRect = * rect;
248
249 m_isDirty = false;
250 m_isDirty = false;
251
252 if (m_cursor.Ok())
253 {
254 m_oldCursor = window->GetCursor();
255 window->SetCursor(m_cursor);
256 }
257
258 window->CaptureMouse();
259
260 // Make a copy of the window so we can repair damage done as the image is
261 // dragged.
262
263 wxSize clientSize;
264 wxPoint pt;
265 if (!m_fullScreen)
266 {
267 clientSize = window->GetClientSize();
268 m_boundingRect.x = 0; m_boundingRect.y = 0;
269 m_boundingRect.width = clientSize.x; m_boundingRect.height = clientSize.y;
270 }
271 else
272 {
273 int w, h;
274 wxDisplaySize(& w, & h);
275 clientSize.x = w; clientSize.y = h;
276 if (rect)
277 {
278 pt.x = m_boundingRect.x; pt.y = m_boundingRect.y;
279 clientSize.x = m_boundingRect.width; clientSize.y = m_boundingRect.height;
280 }
281 else
282 {
283 m_boundingRect.x = 0; m_boundingRect.y = 0;
284 m_boundingRect.width = w; m_boundingRect.height = h;
285 }
286 }
287
288#ifndef wxHAS_NATIVE_OVERLAY
289 wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap);
290
291 if (!backing->Ok() || (backing->GetWidth() < clientSize.x || backing->GetHeight() < clientSize.y))
292 (*backing) = wxBitmap(clientSize.x, clientSize.y);
293#endif // !wxHAS_NATIVE_OVERLAY
294
295 if (!m_fullScreen)
296 {
297 m_windowDC = new wxClientDC(window);
298 }
299 else
300 {
301 m_windowDC = new wxScreenDC;
302
303#if 0
304 // Use m_boundingRect to limit the area considered.
305 ((wxScreenDC*) m_windowDC)->StartDrawingOnTop(rect);
306#endif
307
308 m_windowDC->SetClippingRegion(m_boundingRect.x, m_boundingRect.y,
309 m_boundingRect.width, m_boundingRect.height);
310 }
311
312 return true;
313}
314
315// Begin drag. hotspot is the location of the drag position relative to the upper-left
316// corner of the image. This is full screen only. fullScreenRect gives the
317// position of the window on the screen, to restrict the drag to.
318bool wxGenericDragImage::BeginDrag(const wxPoint& hotspot, wxWindow* window, wxWindow* fullScreenRect)
319{
320 wxRect rect;
321
322 int x = fullScreenRect->GetPosition().x;
323 int y = fullScreenRect->GetPosition().y;
324
325 wxSize sz = fullScreenRect->GetSize();
326
327 if (fullScreenRect->GetParent() && !fullScreenRect->IsKindOf(CLASSINFO(wxFrame)))
328 fullScreenRect->GetParent()->ClientToScreen(& x, & y);
329
330 rect.x = x; rect.y = y;
331 rect.width = sz.x; rect.height = sz.y;
332
333 return BeginDrag(hotspot, window, true, & rect);
334}
335
336// End drag
337bool wxGenericDragImage::EndDrag()
338{
339 if (m_window)
340 {
341#ifdef __WXMSW__
342 // Under Windows we can be pretty sure this test will give
343 // the correct results
344 if (wxWindow::GetCapture() == m_window)
345#endif
346 m_window->ReleaseMouse();
347
348 if (m_cursor.Ok() && m_oldCursor.Ok())
349 {
350 m_window->SetCursor(m_oldCursor);
351 }
352 }
353
354 if (m_windowDC)
355 {
356#ifdef wxHAS_NATIVE_OVERLAY
357 m_overlay.Reset();
358#else
359 m_windowDC->DestroyClippingRegion();
360#endif
361 wxDELETE(m_windowDC);
362 }
363
364#ifndef wxHAS_NATIVE_OVERLAY
365 m_repairBitmap = wxNullBitmap;
366#endif
367
368 return true;
369}
370
371// Move the image: call from OnMouseMove. Pt is in window client coordinates if window
372// is non-NULL, or in screen coordinates if NULL.
373bool wxGenericDragImage::Move(const wxPoint& pt)
374{
375 wxASSERT_MSG( (m_windowDC != NULL), wxT("No window DC in wxGenericDragImage::Move()") );
376
377 wxPoint pt2(pt);
378 if (m_fullScreen)
379 pt2 = m_window->ClientToScreen(pt);
380
381 // Erase at old position, then show at the current position
382 wxPoint oldPos = m_position;
383
384 bool eraseOldImage = (m_isDirty && m_isShown);
385
386 if (m_isShown)
387 RedrawImage(oldPos - m_offset, pt2 - m_offset, eraseOldImage, true);
388
389 m_position = pt2;
390
391 if (m_isShown)
392 m_isDirty = true;
393
394 return true;
395}
396
397bool wxGenericDragImage::Show()
398{
399 wxASSERT_MSG( (m_windowDC != NULL), wxT("No window DC in wxGenericDragImage::Show()") );
400
401 // Show at the current position
402
403 if (!m_isShown)
404 {
405 // This is where we restore the backing bitmap, in case
406 // something has changed on the window.
407
408#ifndef wxHAS_NATIVE_OVERLAY
409 wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap);
410 wxMemoryDC memDC;
411 memDC.SelectObject(* backing);
412
413 UpdateBackingFromWindow(* m_windowDC, memDC, m_boundingRect, wxRect(0, 0, m_boundingRect.width, m_boundingRect.height));
414
415 //memDC.Blit(0, 0, m_boundingRect.width, m_boundingRect.height, m_windowDC, m_boundingRect.x, m_boundingRect.y);
416 memDC.SelectObject(wxNullBitmap);
417#endif // !wxHAS_NATIVE_OVERLAY
418
419 RedrawImage(m_position - m_offset, m_position - m_offset, false, true);
420 }
421
422 m_isShown = true;
423 m_isDirty = true;
424
425 return true;
426}
427
428bool wxGenericDragImage::UpdateBackingFromWindow(wxDC& windowDC, wxMemoryDC& destDC,
429 const wxRect& sourceRect, const wxRect& destRect) const
430{
431 return destDC.Blit(destRect.x, destRect.y, destRect.width, destRect.height, & windowDC,
432 sourceRect.x, sourceRect.y);
433}
434
435bool wxGenericDragImage::Hide()
436{
437 wxASSERT_MSG( (m_windowDC != NULL), wxT("No window DC in wxGenericDragImage::Hide()") );
438
439 // Repair the old position
440
441 if (m_isShown && m_isDirty)
442 {
443 RedrawImage(m_position - m_offset, m_position - m_offset, true, false);
444 }
445
446 m_isShown = false;
447 m_isDirty = false;
448
449 return true;
450}
451
452// More efficient: erase and redraw simultaneously if possible
453bool wxGenericDragImage::RedrawImage(const wxPoint& oldPos,
454 const wxPoint& newPos,
455 bool eraseOld, bool drawNew)
456{
457 if (!m_windowDC)
458 return false;
459
460#ifdef wxHAS_NATIVE_OVERLAY
461 wxUnusedVar(oldPos);
462
463 wxDCOverlay dcoverlay( m_overlay, (wxWindowDC*) m_windowDC ) ;
464 if ( eraseOld )
465 dcoverlay.Clear() ;
466 if (drawNew)
467 DoDrawImage(*m_windowDC, newPos);
468#else // !wxHAS_NATIVE_OVERLAY
469 wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap);
470 if (!backing->Ok())
471 return false;
472
473 wxRect oldRect(GetImageRect(oldPos));
474 wxRect newRect(GetImageRect(newPos));
475
476 wxRect fullRect;
477
478 // Full rect: the combination of both rects
479 if (eraseOld && drawNew)
480 {
481 int oldRight = oldRect.GetRight();
482 int oldBottom = oldRect.GetBottom();
483 int newRight = newRect.GetRight();
484 int newBottom = newRect.GetBottom();
485
486 wxPoint topLeft = wxPoint(wxMin(oldPos.x, newPos.x), wxMin(oldPos.y, newPos.y));
487 wxPoint bottomRight = wxPoint(wxMax(oldRight, newRight), wxMax(oldBottom, newBottom));
488
489 fullRect.x = topLeft.x; fullRect.y = topLeft.y;
490 fullRect.SetRight(bottomRight.x);
491 fullRect.SetBottom(bottomRight.y);
492 }
493 else if (eraseOld)
494 fullRect = oldRect;
495 else if (drawNew)
496 fullRect = newRect;
497
498 // Make the bitmap bigger than it need be, so we don't
499 // keep reallocating all the time.
500 int excess = 50;
501
502 if (!m_repairBitmap.Ok() || (m_repairBitmap.GetWidth() < fullRect.GetWidth() || m_repairBitmap.GetHeight() < fullRect.GetHeight()))
503 {
504 m_repairBitmap = wxBitmap(fullRect.GetWidth() + excess, fullRect.GetHeight() + excess);
505 }
506
507 wxMemoryDC memDC;
508 memDC.SelectObject(* backing);
509
510 wxMemoryDC memDCTemp;
511 memDCTemp.SelectObject(m_repairBitmap);
512
513 // Draw the backing bitmap onto the repair bitmap.
514 // If full-screen, we may have specified the rect on the
515 // screen that we're using for our backing bitmap.
516 // So subtract this when we're blitting from the backing bitmap
517 // (translate from screen to backing-bitmap coords).
518
519 memDCTemp.Blit(0, 0, fullRect.GetWidth(), fullRect.GetHeight(), & memDC, fullRect.x - m_boundingRect.x, fullRect.y - m_boundingRect.y);
520
521 // If drawing, draw the image onto the mem DC
522 if (drawNew)
523 {
524 wxPoint pos(newPos.x - fullRect.x, newPos.y - fullRect.y) ;
525 DoDrawImage(memDCTemp, pos);
526 }
527
528 // Now blit to the window
529 // Finally, blit the temp mem DC to the window.
530 m_windowDC->Blit(fullRect.x, fullRect.y, fullRect.width, fullRect.height, & memDCTemp, 0, 0);
531
532 memDCTemp.SelectObject(wxNullBitmap);
533 memDC.SelectObject(wxNullBitmap);
534#endif // wxHAS_NATIVE_OVERLAY/!wxHAS_NATIVE_OVERLAY
535
536 return true;
537}
538
539// Override this if you are using a virtual image (drawing your own image)
540bool wxGenericDragImage::DoDrawImage(wxDC& dc, const wxPoint& pos) const
541{
542 if (m_bitmap.Ok())
543 {
544 dc.DrawBitmap(m_bitmap, pos.x, pos.y, (m_bitmap.GetMask() != 0));
545 return true;
546 }
547 else if (m_icon.Ok())
548 {
549 dc.DrawIcon(m_icon, pos.x, pos.y);
550 return true;
551 }
552 else
553 return false;
554}
555
556// Override this if you are using a virtual image (drawing your own image)
557wxRect wxGenericDragImage::GetImageRect(const wxPoint& pos) const
558{
559 if (m_bitmap.Ok())
560 {
561 return wxRect(pos.x, pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight());
562 }
563 else if (m_icon.Ok())
564 {
565 return wxRect(pos.x, pos.y, m_icon.GetWidth(), m_icon.GetHeight());
566 }
567 else
568 {
569 return wxRect(pos.x, pos.y, 0, 0);
570 }
571}
572
573#endif // wxUSE_DRAGIMAGE