warnings from FreeBSD compilation log removed
[wxWidgets.git] / src / generic / dragimgg.cpp
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
61 IMPLEMENT_DYNAMIC_CLASS(wxGenericDragImage, wxObject)
62
63 // ============================================================================
64 // implementation
65 // ============================================================================
66
67 // ----------------------------------------------------------------------------
68 // wxGenericDragImage ctors/dtor
69 // ----------------------------------------------------------------------------
70
71 wxGenericDragImage::wxGenericDragImage()
72 {
73 Init();
74 }
75
76 wxGenericDragImage::~wxGenericDragImage()
77 {
78 if (m_windowDC)
79 {
80 delete m_windowDC;
81 }
82 }
83
84 void 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
101 bool 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
114 bool 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
127 bool 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
172 bool 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
179 bool wxGenericDragImage::Create(const wxListCtrl& listCtrl, long id)
180 {
181 wxString str = listCtrl.GetItemText(id);
182 return Create(str);
183 }
184
185 // Begin drag
186 bool wxGenericDragImage::BeginDrag(const wxPoint& WXUNUSED(hotspot),
187 wxWindow* window,
188 bool fullScreen,
189 wxRect* rect)
190 {
191 wxASSERT_MSG( (window != 0), wxT("Window must not be null in BeginDrag."));
192
193 m_window = window;
194 m_fullScreen = fullScreen;
195
196 if (rect)
197 m_boundingRect = * rect;
198
199 m_isDirty = FALSE;
200 m_isDirty = FALSE;
201
202 if (window)
203 {
204 window->CaptureMouse();
205
206 if (m_cursor.Ok())
207 {
208 m_oldCursor = window->GetCursor();
209 window->SetCursor(m_cursor);
210 }
211 }
212
213 // Make a copy of the window so we can repair damage done as the image is
214 // dragged.
215
216 wxSize clientSize;
217 wxPoint pt(0, 0);
218 if (!m_fullScreen)
219 {
220 clientSize = window->GetClientSize();
221 m_boundingRect.x = 0; m_boundingRect.y = 0;
222 m_boundingRect.width = clientSize.x; m_boundingRect.height = clientSize.y;
223 }
224 else
225 {
226 int w, h;
227 wxDisplaySize(& w, & h);
228 clientSize.x = w; clientSize.y = h;
229 if (rect)
230 {
231 pt.x = m_boundingRect.x; pt.y = m_boundingRect.y;
232 clientSize.x = m_boundingRect.width; clientSize.y = m_boundingRect.height;
233 }
234 else
235 {
236 m_boundingRect.x = 0; m_boundingRect.y = 0;
237 m_boundingRect.width = w; m_boundingRect.height = h;
238 }
239 }
240
241 if (!m_backingBitmap.Ok() || (m_backingBitmap.GetWidth() < clientSize.x || m_backingBitmap.GetHeight() < clientSize.y))
242 m_backingBitmap = wxBitmap(clientSize.x, clientSize.y);
243
244 if (!m_fullScreen)
245 m_windowDC = new wxClientDC(window);
246 else
247 {
248 m_windowDC = new wxScreenDC;
249
250 #if 0
251 // Use m_boundingRect to limit the area considered.
252 ((wxScreenDC*) m_windowDC)->StartDrawingOnTop(rect);
253 #endif
254
255 m_windowDC->SetClippingRegion(m_boundingRect.x, m_boundingRect.y,
256 m_boundingRect.width, m_boundingRect.height);
257 }
258
259 return TRUE;
260 }
261
262 // Begin drag. hotspot is the location of the drag position relative to the upper-left
263 // corner of the image. This is full screen only. fullScreenRect gives the
264 // position of the window on the screen, to restrict the drag to.
265 bool wxGenericDragImage::BeginDrag(const wxPoint& hotspot, wxWindow* window, wxWindow* fullScreenRect)
266 {
267 wxRect rect;
268
269 int x = fullScreenRect->GetPosition().x;
270 int y = fullScreenRect->GetPosition().y;
271
272 wxSize sz = fullScreenRect->GetSize();
273
274 if (fullScreenRect->GetParent() && !fullScreenRect->IsKindOf(CLASSINFO(wxFrame)))
275 fullScreenRect->GetParent()->ClientToScreen(& x, & y);
276
277 rect.x = x; rect.y = y;
278 rect.width = sz.x; rect.height = sz.y;
279
280 return BeginDrag(hotspot, window, TRUE, & rect);
281 }
282
283 // End drag
284 bool wxGenericDragImage::EndDrag()
285 {
286 if (m_window)
287 {
288 m_window->ReleaseMouse();
289 if (m_cursor.Ok() && m_oldCursor.Ok())
290 {
291 m_window->SetCursor(m_oldCursor);
292 }
293 }
294
295 if (m_windowDC)
296 {
297 m_windowDC->DestroyClippingRegion();
298 delete m_windowDC;
299 m_windowDC = (wxDC*) NULL;
300 }
301
302 m_repairBitmap = wxNullBitmap;
303
304 return TRUE;
305 }
306
307 // Move the image: call from OnMouseMove. Pt is in window client coordinates if window
308 // is non-NULL, or in screen coordinates if NULL.
309 bool wxGenericDragImage::Move(const wxPoint& pt)
310 {
311 wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), "No window DC in wxGenericDragImage::Move()" );
312
313 // Erase at old position, then show at the current position
314 wxPoint oldPos = m_position;
315
316 bool eraseOldImage = (m_isDirty && m_isShown);
317
318 if (m_isShown)
319 RedrawImage(oldPos, pt, eraseOldImage, TRUE);
320
321 m_position = pt;
322
323 if (m_isShown)
324 m_isDirty = TRUE;
325
326 return TRUE;
327 }
328
329 bool wxGenericDragImage::Show()
330 {
331 wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), "No window DC in wxGenericDragImage::Show()" );
332
333 // Show at the current position
334
335 if (!m_isShown)
336 {
337 // This is where we restore the backing bitmap, in case
338 // something has changed on the window.
339
340 wxMemoryDC memDC;
341 memDC.SelectObject(m_backingBitmap);
342 memDC.Blit(0, 0, m_boundingRect.width, m_boundingRect.height, m_windowDC, m_boundingRect.x, m_boundingRect.y);
343 memDC.SelectObject(wxNullBitmap);
344
345 RedrawImage(m_position, m_position, FALSE, TRUE);
346 }
347
348 m_isShown = TRUE;
349 m_isDirty = TRUE;
350
351 return TRUE;
352 }
353
354 bool wxGenericDragImage::Hide()
355 {
356 wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), "No window DC in wxGenericDragImage::Hide()" );
357
358 // Repair the old position
359
360 if (m_isShown && m_isDirty)
361 {
362 RedrawImage(m_position, m_position, TRUE, FALSE);
363 }
364
365 m_isShown = FALSE;
366 m_isDirty = FALSE;
367
368 return TRUE;
369 }
370
371 // More efficient: erase and redraw simultaneously if possible
372 bool wxGenericDragImage::RedrawImage(const wxPoint& oldPos, const wxPoint& newPos,
373 bool eraseOld, bool drawNew)
374 {
375 if (!m_windowDC)
376 return FALSE;
377
378 if (!m_backingBitmap.Ok())
379 return FALSE;
380
381 wxRect oldRect(GetImageRect(oldPos));
382 wxRect newRect(GetImageRect(newPos));
383
384 wxRect fullRect;
385
386 // Full rect: the combination of both rects
387 if (eraseOld && drawNew)
388 {
389 int oldRight = oldRect.GetRight();
390 int oldBottom = oldRect.GetBottom();
391 int newRight = newRect.GetRight();
392 int newBottom = newRect.GetBottom();
393
394 wxPoint topLeft = wxPoint(wxMin(oldPos.x, newPos.x), wxMin(oldPos.y, newPos.y));
395 wxPoint bottomRight = wxPoint(wxMax(oldRight, newRight), wxMax(oldBottom, newBottom));
396
397 fullRect.x = topLeft.x; fullRect.y = topLeft.y;
398 fullRect.SetRight(bottomRight.x);
399 fullRect.SetBottom(bottomRight.y);
400 }
401 else if (eraseOld)
402 fullRect = oldRect;
403 else if (drawNew)
404 fullRect = newRect;
405
406 // Make the bitmap bigger than it need be, so we don't
407 // keep reallocating all the time.
408 int excess = 50;
409
410 if (!m_repairBitmap.Ok() || (m_repairBitmap.GetWidth() < fullRect.GetWidth() || m_repairBitmap.GetHeight() < fullRect.GetHeight()))
411 {
412 m_repairBitmap = wxBitmap(fullRect.GetWidth() + excess, fullRect.GetHeight() + excess);
413 }
414
415 wxMemoryDC memDC;
416 memDC.SelectObject(m_backingBitmap);
417
418 wxMemoryDC memDCTemp;
419 memDCTemp.SelectObject(m_repairBitmap);
420
421 // Draw the backing bitmap onto the repair bitmap.
422 // If full-screen, we may have specified the rect on the
423 // screen that we're using for our backing bitmap.
424 // So subtract this when we're blitting from the backing bitmap
425 // (translate from screen to backing-bitmap coords).
426
427 memDCTemp.Blit(0, 0, fullRect.GetWidth(), fullRect.GetHeight(), & memDC, fullRect.x - m_boundingRect.x, fullRect.y - m_boundingRect.y);
428
429 // If drawing, draw the image onto the mem DC
430 if (drawNew)
431 {
432 int x = newPos.x - fullRect.x;
433 int y = newPos.y - fullRect.y;
434 if (m_bitmap.Ok())
435 memDCTemp.DrawBitmap(m_bitmap, x, y, (m_bitmap.GetMask() != 0));
436 else if (m_icon.Ok())
437 memDCTemp.DrawIcon(m_icon, x, y);
438 }
439
440 // Now blit to the window
441 // Finally, blit the temp mem DC to the window.
442 m_windowDC->Blit(fullRect.x, fullRect.y, fullRect.width, fullRect.height, & memDCTemp, 0, 0);
443
444 memDCTemp.SelectObject(wxNullBitmap);
445 memDC.SelectObject(wxNullBitmap);
446
447 return TRUE;
448 }
449
450 wxRect wxGenericDragImage::GetImageRect(const wxPoint& pos) const
451 {
452 if (m_bitmap.Ok())
453 {
454 return wxRect(pos.x, pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight());
455 }
456 else if (m_icon.Ok())
457 {
458 return wxRect(pos.x, pos.y, m_icon.GetWidth(), m_icon.GetHeight());
459 }
460 else
461 {
462 return wxRect(pos.x, pos.y, 0, 0);
463 }
464 }
465