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