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