Standardize on using sample.rc and sample icon in all the samples, it was confusing that some of them used it and other didn't, without any apparent logic. Remove the now unnecessary icon files, including the dialogs sample icon which seemed to be corrupted (this closes #11146). Also replace multiple OS/2 resource files with a single one in the sample directory. The OS/2 projects/makefiles would need to be updated to use them. Remove dialogs sample icon. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64645 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
510 lines
13 KiB
C++
510 lines
13 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: dragimag.cpp
|
|
// Purpose: wxDragImage sample
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 28/2/2000
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) Julian Smart
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// For compilers that support precompilation, includes "wx/wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
#include "wx/image.h"
|
|
|
|
// Under Windows, change this to 1
|
|
// to use wxGenericDragImage
|
|
|
|
#define wxUSE_GENERIC_DRAGIMAGE 1
|
|
|
|
#if wxUSE_GENERIC_DRAGIMAGE
|
|
#include "wx/generic/dragimgg.h"
|
|
#define wxDragImage wxGenericDragImage
|
|
#else
|
|
#include "wx/dragimag.h"
|
|
#endif
|
|
|
|
#include "dragimag.h"
|
|
|
|
#if !defined(__WXMSW__) && !defined(__WXPM__)
|
|
#include "../sample.xpm"
|
|
#include "dragicon.xpm"
|
|
#endif
|
|
|
|
// main program
|
|
|
|
IMPLEMENT_APP(MyApp)
|
|
|
|
// MyCanvas
|
|
|
|
IMPLEMENT_CLASS(MyCanvas, wxScrolledWindow)
|
|
|
|
BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
|
|
EVT_PAINT(MyCanvas::OnPaint)
|
|
EVT_ERASE_BACKGROUND(MyCanvas::OnEraseBackground)
|
|
EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
|
|
END_EVENT_TABLE()
|
|
|
|
MyCanvas::MyCanvas( wxWindow *parent, wxWindowID id,
|
|
const wxPoint &pos, const wxSize &size )
|
|
: wxScrolledWindow( parent, id, pos, size, wxSUNKEN_BORDER )
|
|
{
|
|
SetBackgroundColour(* wxWHITE);
|
|
|
|
SetCursor(wxCursor(wxCURSOR_ARROW));
|
|
|
|
m_dragMode = TEST_DRAG_NONE;
|
|
m_draggedShape = (DragShape*) NULL;
|
|
m_dragImage = (wxDragImage*) NULL;
|
|
m_currentlyHighlighted = (DragShape*) NULL;
|
|
}
|
|
|
|
MyCanvas::~MyCanvas()
|
|
{
|
|
ClearShapes();
|
|
|
|
if (m_dragImage)
|
|
delete m_dragImage;
|
|
}
|
|
|
|
void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
|
|
{
|
|
wxPaintDC dc( this );
|
|
PrepareDC( dc );
|
|
|
|
DrawShapes(dc);
|
|
}
|
|
|
|
void MyCanvas::OnEraseBackground(wxEraseEvent& event)
|
|
{
|
|
if (wxGetApp().GetBackgroundBitmap().Ok())
|
|
{
|
|
wxSize sz = GetClientSize();
|
|
wxRect rect(0, 0, sz.x, sz.y);
|
|
|
|
if (event.GetDC())
|
|
{
|
|
wxGetApp().TileBitmap(rect, *(event.GetDC()), wxGetApp().GetBackgroundBitmap());
|
|
}
|
|
else
|
|
{
|
|
wxClientDC dc(this);
|
|
wxGetApp().TileBitmap(rect, dc, wxGetApp().GetBackgroundBitmap());
|
|
}
|
|
}
|
|
else
|
|
event.Skip(); // The official way of doing it
|
|
}
|
|
|
|
void MyCanvas::OnMouseEvent(wxMouseEvent& event)
|
|
{
|
|
if (event.LeftDown())
|
|
{
|
|
DragShape* shape = FindShape(event.GetPosition());
|
|
if (shape)
|
|
{
|
|
// We tentatively start dragging, but wait for
|
|
// mouse movement before dragging properly.
|
|
|
|
m_dragMode = TEST_DRAG_START;
|
|
m_dragStartPos = event.GetPosition();
|
|
m_draggedShape = shape;
|
|
}
|
|
}
|
|
else if (event.LeftUp() && m_dragMode != TEST_DRAG_NONE)
|
|
{
|
|
// Finish dragging
|
|
|
|
m_dragMode = TEST_DRAG_NONE;
|
|
|
|
if (!m_draggedShape || !m_dragImage)
|
|
return;
|
|
|
|
m_draggedShape->SetPosition(m_draggedShape->GetPosition()
|
|
+ event.GetPosition() - m_dragStartPos);
|
|
|
|
m_dragImage->Hide();
|
|
m_dragImage->EndDrag();
|
|
delete m_dragImage;
|
|
m_dragImage = NULL;
|
|
|
|
m_draggedShape->SetShow(true);
|
|
|
|
m_currentlyHighlighted = (DragShape*) NULL;
|
|
|
|
m_draggedShape = (DragShape*) NULL;
|
|
|
|
Refresh(true);
|
|
}
|
|
else if (event.Dragging() && m_dragMode != TEST_DRAG_NONE)
|
|
{
|
|
if (m_dragMode == TEST_DRAG_START)
|
|
{
|
|
// We will start dragging if we've moved beyond a couple of pixels
|
|
|
|
int tolerance = 2;
|
|
int dx = abs(event.GetPosition().x - m_dragStartPos.x);
|
|
int dy = abs(event.GetPosition().y - m_dragStartPos.y);
|
|
if (dx <= tolerance && dy <= tolerance)
|
|
return;
|
|
|
|
// Start the drag.
|
|
m_dragMode = TEST_DRAG_DRAGGING;
|
|
|
|
if (m_dragImage)
|
|
delete m_dragImage;
|
|
|
|
// Erase the dragged shape from the canvas
|
|
m_draggedShape->SetShow(false);
|
|
|
|
// redraw immediately
|
|
Refresh(true);
|
|
Update();
|
|
|
|
switch (m_draggedShape->GetDragMethod())
|
|
{
|
|
case SHAPE_DRAG_BITMAP:
|
|
{
|
|
m_dragImage = new MyDragImage(this, m_draggedShape->GetBitmap(), wxCursor(wxCURSOR_HAND));
|
|
break;
|
|
}
|
|
case SHAPE_DRAG_TEXT:
|
|
{
|
|
m_dragImage = new MyDragImage(this, wxString(wxT("Dragging some test text")), wxCursor(wxCURSOR_HAND));
|
|
break;
|
|
}
|
|
case SHAPE_DRAG_ICON:
|
|
{
|
|
m_dragImage = new MyDragImage(this, wxICON(dragicon), wxCursor(wxCURSOR_HAND));
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool fullScreen = wxGetApp().GetUseScreen();
|
|
|
|
// The offset between the top-left of the shape image and the current shape position
|
|
wxPoint beginDragHotSpot = m_dragStartPos - m_draggedShape->GetPosition();
|
|
|
|
// Now we do this inside the implementation: always assume
|
|
// coordinates relative to the capture window (client coordinates)
|
|
|
|
//if (fullScreen)
|
|
// beginDragHotSpot -= ClientToScreen(wxPoint(0, 0));
|
|
|
|
if (!m_dragImage->BeginDrag(beginDragHotSpot, this, fullScreen))
|
|
{
|
|
delete m_dragImage;
|
|
m_dragImage = (wxDragImage*) NULL;
|
|
m_dragMode = TEST_DRAG_NONE;
|
|
|
|
} else
|
|
{
|
|
m_dragImage->Move(event.GetPosition());
|
|
m_dragImage->Show();
|
|
}
|
|
}
|
|
else if (m_dragMode == TEST_DRAG_DRAGGING)
|
|
{
|
|
// We're currently dragging. See if we're over another shape.
|
|
DragShape* onShape = FindShape(event.GetPosition());
|
|
|
|
bool mustUnhighlightOld = false;
|
|
bool mustHighlightNew = false;
|
|
|
|
if (m_currentlyHighlighted)
|
|
{
|
|
if ((onShape == (DragShape*) NULL) || (m_currentlyHighlighted != onShape))
|
|
mustUnhighlightOld = true;
|
|
}
|
|
|
|
if (onShape && (onShape != m_currentlyHighlighted) && onShape->IsShown())
|
|
mustHighlightNew = true;
|
|
|
|
if (mustUnhighlightOld || mustHighlightNew)
|
|
m_dragImage->Hide();
|
|
|
|
// Now with the drag image switched off, we can change the window contents.
|
|
if (mustUnhighlightOld)
|
|
m_currentlyHighlighted = (DragShape*) NULL;
|
|
|
|
if (mustHighlightNew)
|
|
m_currentlyHighlighted = onShape;
|
|
|
|
if (mustUnhighlightOld || mustHighlightNew)
|
|
{
|
|
Refresh(mustUnhighlightOld);
|
|
Update();
|
|
}
|
|
|
|
// Move and show the image again
|
|
m_dragImage->Move(event.GetPosition());
|
|
|
|
if (mustUnhighlightOld || mustHighlightNew)
|
|
m_dragImage->Show();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MyCanvas::DrawShapes(wxDC& dc)
|
|
{
|
|
wxList::compatibility_iterator node = m_displayList.GetFirst();
|
|
while (node)
|
|
{
|
|
DragShape* shape = (DragShape*) node->GetData();
|
|
if (shape->IsShown() && m_draggedShape != shape)
|
|
{
|
|
shape->Draw(dc, (m_currentlyHighlighted == shape));
|
|
}
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
void MyCanvas::EraseShape(DragShape* shape, wxDC& dc)
|
|
{
|
|
wxSize sz = GetClientSize();
|
|
wxRect rect(0, 0, sz.x, sz.y);
|
|
|
|
wxRect rect2(shape->GetRect());
|
|
dc.SetClippingRegion(rect2.x, rect2.y, rect2.width, rect2.height);
|
|
|
|
wxGetApp().TileBitmap(rect, dc, wxGetApp().GetBackgroundBitmap());
|
|
|
|
dc.DestroyClippingRegion();
|
|
}
|
|
|
|
void MyCanvas::ClearShapes()
|
|
{
|
|
wxList::compatibility_iterator node = m_displayList.GetFirst();
|
|
while (node)
|
|
{
|
|
DragShape* shape = (DragShape*) node->GetData();
|
|
delete shape;
|
|
node = node->GetNext();
|
|
}
|
|
m_displayList.Clear();
|
|
}
|
|
|
|
DragShape* MyCanvas::FindShape(const wxPoint& pt) const
|
|
{
|
|
wxList::compatibility_iterator node = m_displayList.GetFirst();
|
|
while (node)
|
|
{
|
|
DragShape* shape = (DragShape*) node->GetData();
|
|
if (shape->HitTest(pt))
|
|
return shape;
|
|
node = node->GetNext();
|
|
}
|
|
return (DragShape*) NULL;
|
|
}
|
|
|
|
// MyFrame
|
|
IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
|
|
|
|
BEGIN_EVENT_TABLE(MyFrame,wxFrame)
|
|
EVT_MENU (wxID_ABOUT, MyFrame::OnAbout)
|
|
EVT_MENU (wxID_EXIT, MyFrame::OnQuit)
|
|
END_EVENT_TABLE()
|
|
|
|
MyFrame::MyFrame()
|
|
: wxFrame( (wxFrame *)NULL, wxID_ANY, wxT("wxDragImage sample"),
|
|
wxPoint(20,20), wxSize(470,360) )
|
|
{
|
|
wxMenu *file_menu = new wxMenu();
|
|
file_menu->Append( wxID_ABOUT, wxT("&About..."));
|
|
file_menu->AppendCheckItem( TEST_USE_SCREEN, wxT("&Use whole screen for dragging"), wxT("Use whole screen"));
|
|
file_menu->Append( wxID_EXIT, wxT("E&xit"));
|
|
|
|
wxMenuBar *menu_bar = new wxMenuBar();
|
|
menu_bar->Append(file_menu, wxT("&File"));
|
|
|
|
SetIcon(wxICON(sample));
|
|
SetMenuBar( menu_bar );
|
|
|
|
#if wxUSE_STATUSBAR
|
|
CreateStatusBar(2);
|
|
int widths[] = { -1, 100 };
|
|
SetStatusWidths( 2, widths );
|
|
#endif // wxUSE_STATUSBAR
|
|
|
|
m_canvas = new MyCanvas( this, wxID_ANY, wxPoint(0,0), wxSize(10,10) );
|
|
}
|
|
|
|
void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )
|
|
{
|
|
Close( true );
|
|
}
|
|
|
|
void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) )
|
|
{
|
|
(void)wxMessageBox( wxT("wxDragImage demo\n")
|
|
wxT("Julian Smart (c) 2000"),
|
|
wxT("About wxDragImage Demo"),
|
|
wxICON_INFORMATION | wxOK );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// MyApp
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BEGIN_EVENT_TABLE(MyApp, wxApp)
|
|
EVT_MENU(TEST_USE_SCREEN, MyApp::OnUseScreen)
|
|
END_EVENT_TABLE()
|
|
|
|
MyApp::MyApp()
|
|
{
|
|
// Drag across whole screen
|
|
m_useScreen = false;
|
|
}
|
|
|
|
bool MyApp::OnInit()
|
|
{
|
|
if ( !wxApp::OnInit() )
|
|
return false;
|
|
|
|
#if wxUSE_LIBPNG
|
|
wxImage::AddHandler( new wxPNGHandler );
|
|
#endif
|
|
|
|
wxImage image;
|
|
if (image.LoadFile(wxT("backgrnd.png"), wxBITMAP_TYPE_PNG))
|
|
{
|
|
m_background = wxBitmap(image);
|
|
}
|
|
|
|
MyFrame *frame = new MyFrame();
|
|
|
|
wxString rootName(wxT("shape0"));
|
|
|
|
for (int i = 1; i < 4; i++)
|
|
{
|
|
/* For some reason under wxX11, the 2nd LoadFile in this loop fails, with
|
|
a BadMatch inside CreateFromImage (inside ConvertToBitmap). This happens even if you copy
|
|
the first file over the second file. */
|
|
if (image.LoadFile(wxString::Format("%s%d.png", rootName, i), wxBITMAP_TYPE_PNG))
|
|
{
|
|
DragShape* newShape = new DragShape(wxBitmap(image));
|
|
newShape->SetPosition(wxPoint(i*50, i*50));
|
|
|
|
if (i == 2)
|
|
newShape->SetDragMethod(SHAPE_DRAG_TEXT);
|
|
else if (i == 3)
|
|
newShape->SetDragMethod(SHAPE_DRAG_ICON);
|
|
else
|
|
newShape->SetDragMethod(SHAPE_DRAG_BITMAP);
|
|
frame->GetCanvas()->GetDisplayList().Append(newShape);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
// Under Motif or GTK, this demonstrates that
|
|
// wxScreenDC only gets the root window content.
|
|
// We need to be able to copy the overall content
|
|
// for full-screen dragging to work.
|
|
int w, h;
|
|
wxDisplaySize(& w, & h);
|
|
wxBitmap bitmap(w, h);
|
|
|
|
wxScreenDC dc;
|
|
wxMemoryDC memDC;
|
|
memDC.SelectObject(bitmap);
|
|
memDC.Blit(0, 0, w, h, & dc, 0, 0);
|
|
memDC.SelectObject(wxNullBitmap);
|
|
m_background = bitmap;
|
|
#endif
|
|
|
|
frame->Show( true );
|
|
|
|
return true;
|
|
}
|
|
|
|
int MyApp::OnExit()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
bool MyApp::TileBitmap(const wxRect& rect, wxDC& dc, wxBitmap& bitmap)
|
|
{
|
|
int w = bitmap.GetWidth();
|
|
int h = bitmap.GetHeight();
|
|
|
|
int i, j;
|
|
for (i = rect.x; i < rect.x + rect.width; i += w)
|
|
{
|
|
for (j = rect.y; j < rect.y + rect.height; j+= h)
|
|
dc.DrawBitmap(bitmap, i, j);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MyApp::OnUseScreen(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
m_useScreen = !m_useScreen;
|
|
}
|
|
|
|
// DragShape
|
|
|
|
DragShape::DragShape(const wxBitmap& bitmap)
|
|
{
|
|
m_bitmap = bitmap;
|
|
m_pos.x = 0;
|
|
m_pos.y = 0;
|
|
m_dragMethod = SHAPE_DRAG_BITMAP;
|
|
m_show = true;
|
|
}
|
|
|
|
bool DragShape::HitTest(const wxPoint& pt) const
|
|
{
|
|
wxRect rect(GetRect());
|
|
return rect.Contains(pt.x, pt.y);
|
|
}
|
|
|
|
bool DragShape::Draw(wxDC& dc, bool highlight)
|
|
{
|
|
if (m_bitmap.Ok())
|
|
{
|
|
wxMemoryDC memDC;
|
|
memDC.SelectObject(m_bitmap);
|
|
|
|
dc.Blit(m_pos.x, m_pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight(),
|
|
& memDC, 0, 0, wxCOPY, true);
|
|
|
|
if (highlight)
|
|
{
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
|
dc.DrawRectangle(m_pos.x, m_pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// MyDragImage
|
|
|
|
// On some platforms, notably Mac OS X with Core Graphics, we can't blit from
|
|
// a window, so we need to draw the background explicitly.
|
|
bool MyDragImage::UpdateBackingFromWindow(wxDC& WXUNUSED(windowDC), wxMemoryDC& destDC, const wxRect& WXUNUSED(sourceRect),
|
|
const wxRect& destRect) const
|
|
{
|
|
destDC.SetClippingRegion(destRect);
|
|
|
|
if (wxGetApp().GetBackgroundBitmap().Ok())
|
|
wxGetApp().TileBitmap(destRect, destDC, wxGetApp().GetBackgroundBitmap());
|
|
|
|
m_canvas->DrawShapes(destDC);
|
|
return true;
|
|
}
|
|
|