Cursor and insert/delete work much better now, code streamlined, still

a minor problem left.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@507 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Karsten Ballüder
1998-08-12 08:33:34 +00:00
parent 3b9261289f
commit 3908d01eab
7 changed files with 249 additions and 176 deletions

View File

@@ -6,10 +6,16 @@
* $Id$ *
* *
* $Log$
* Revision 1.1 1998/06/29 12:44:36 KB
* Added my wxWindows based layout engine to the repository.
* It arranges text and graphics for display on a wxDC.
* This code is licensed under the LGPL.
* Revision 1.2 1998/08/12 08:33:23 KB
* Cursor and insert/delete work much better now, code streamlined, still
* a minor problem left.
*
* Revision 1.6 1998/07/08 11:56:56 KB
* M compiles and runs on Solaris 2.5/gcc 2.8/c-client gso
*
* Revision 1.5 1998/06/27 20:07:18 KB
* several bug fixes for kbList
* started adding my layout stuff
*
* Revision 1.1.1.1 1998/06/13 21:51:12 karsten
* initial code
@@ -34,8 +40,11 @@
# pragma implementation "kbList.h"
#endif
#include "kbList.h"
#ifdef M_BASEDIR
# include "Mconfig.h"
#endif
#include "kbList.h"
kbListNode::kbListNode( void *ielement,
kbListNode *iprev,
@@ -178,11 +187,7 @@ kbList::insert(kbList::iterator & i, void *element)
else if(i.Node() == first)
{
push_front(element);
return;
}
else if(i.Node() == last)
{
push_back(element);
i = first;
return;
}
i = kbList::iterator(new kbListNode(element, i.Node()->prev, i.Node()));

View File

@@ -4,14 +4,6 @@
* (C) 1998 by Karsten Ball<6C>der (Ballueder@usa.net) *
* *
* $Id$
* $Log$
* Revision 1.1 1998/06/29 12:44:36 KB
* Added my wxWindows based layout engine to the repository.
* It arranges text and graphics for display on a wxDC.
* This code is licensed under the LGPL.
*
* Revision 1.6 1998/06/27 20:06:10 KB
* Added my layout code.
*
*******************************************************************/
@@ -209,7 +201,7 @@ public:
bool empty(void) const
{ return first == NULL ; }
private:
protected:
/// if true, list owns entries
bool ownsEntries;
/// pointer to first element in list
@@ -217,6 +209,7 @@ private:
/// pointer to last element in list
kbListNode *last;
private:
/// forbid copy construction
kbList(kbList const &foo);
/// forbid assignments
@@ -251,7 +244,7 @@ public: \
/* the cast is needed for MS VC++ 5.0 */ \
{ return (type *)((kbList::iterator *)this)->operator*() ; } \
}; \
inline name(bool ownsEntriesFlag = true) \
inline name(bool ownsEntriesFlag = FALSE) \
: kbList(ownsEntriesFlag) {} \
\
inline void push_back(type *element) \
@@ -269,7 +262,7 @@ public: \
inline void insert(iterator & i, type *element) \
{ kbList::insert(i, (void *) element); } \
\
void erase(iterator & i) \
inline void erase(iterator & i) \
{ kbList::erase(i); } \
\
inline iterator begin(void) const \
@@ -280,7 +273,22 @@ public: \
\
inline iterator tail(void) const \
{ return kbList::tail(); } \
}
~name() \
{ \
kbListNode *next; \
while ( first != NULL ) \
{ \
next = first->next; \
if(ownsEntries) \
delete typecast(first->element); \
delete first; \
first = next; \
} \
} \
private: \
inline type * typecast(void *ptr) \
{ return (type *) ptr; } \
}
#ifdef MCONFIG_H
/// define the most commonly used list type once:

View File

@@ -31,7 +31,7 @@ IMPLEMENT_APP(MyApp)
//-----------------------------------------------------------------------------
enum ids{ ID_EDIT = 1, ID_ADD_SAMPLE, ID_CLEAR, ID_PRINT, ID_DPRINT,
ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT };
ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT, ID_TEST };
IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
@@ -58,6 +58,7 @@ IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
file_menu->Append( ID_DPRINT, "Direct Print");
file_menu->Append( ID_TEXT, "Export Text");
file_menu->Append( ID_HTML, "Export HTML");
file_menu->Append( ID_TEST, "Test");
file_menu->Append( ID_QUIT, "Exit");
wxMenuBar *menu_bar = new wxMenuBar();
@@ -217,6 +218,15 @@ void MyFrame::OnCommand( wxCommandEvent &event )
case ID_CLICK:
cerr << "Received click event." << endl;
break;
case ID_TEST:
{
Clear();
m_lwin->GetLayoutList().LineBreak();
m_lwin->GetLayoutList().Insert("abc");
m_lwin->GetLayoutList().LineBreak();
m_lwin->GetLayoutList().Insert("def");
break;
}
case ID_HTML:
{
wxLayoutExportObject *export;

View File

@@ -22,12 +22,19 @@
#pragma implementation "wxllist.h"
#endif
#include "wxllist.h"
#include "iostream.h"
// these two lines are for use in M:
//#include "Mpch.h"
//#include "gui/wxllist.h"
#include <wx/dc.h>
#include <wx/postscrp.h>
#include <wx/print.h>
#include "wxllist.h"
#ifndef USE_PCH
# include "iostream.h"
# include <wx/dc.h>
# include <wx/postscrp.h>
# include <wx/print.h>
#endif
#define BASELINESTRETCH 12
@@ -43,13 +50,13 @@ wxLayoutObjectBase::Debug(void)
<< GetSize(&bl).y << " bl=" << bl;
}
# define VAR(x) cerr << #x"=" << x << endl;
# define DBG_POINT(p) cerr << #p << ": " << p.x << ',' << p.y << endl
# define TRACE(f) cerr << #f":" << endl;
# define WXL_VAR(x) cerr << #x"=" << x << endl;
# define WXL_DBG_POINT(p) cerr << #p << ": " << p.x << ',' << p.y << endl
# define WXL_TRACE(f) cerr << #f":" << endl;
#else
# define VAR(x)
# define DBG_POINT(p)
# define TRACE(f)
# define WXL_VAR(x)
# define WXL_DBG_POINT(p)
# define WXL_TRACE(f)
#endif
//-------------------------- wxLayoutObjectText
@@ -99,8 +106,8 @@ wxLayoutObjectText::Debug(void)
//-------------------------- wxLayoutObjectIcon
wxLayoutObjectIcon::wxLayoutObjectIcon(wxIcon *icon)
: m_Icon(icon)
{
m_Icon = icon;
}
void
@@ -205,7 +212,7 @@ wxLayoutList::SetFont(int family, int size, int style, int weight,
if(size != -1) m_FontPtSize = size;
if(style != -1) m_FontStyle = style;
if(weight != -1) m_FontWeight = weight;
if(underline != -1) m_FontUnderline = underline;
if(underline != -1) m_FontUnderline = underline != 0;
if(fg != NULL) m_ColourFG = fg;
if(bg != NULL) m_ColourBG = bg;
@@ -265,6 +272,9 @@ wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const &findCoords)
CoordType baseLine = m_FontPtSize;
CoordType baseLineSkip = (BASELINESTRETCH * baseLine)/10;
// where to draw the cursor
wxPoint cursorPosition, cursorSize;
// we trace the objects' cursor positions so we can draw the cursor
wxPoint cursor = wxPoint(0,0);
// the cursor position inside the object
@@ -295,7 +305,7 @@ wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const &findCoords)
#endif
dc.IsKindOf(CLASSINFO(wxPostScriptDC)))
{
VAR(wxThePrintSetupData);
WXL_VAR(wxThePrintSetupData);
dc.GetSize(&pageWidth, &pageHeight);
dc.StartDoc(_("Printing..."));
@@ -314,7 +324,7 @@ wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const &findCoords)
position.y = margins.right;
position.x = margins.left;
VAR(findObject); VAR(findCoords.x); VAR(findCoords.y);
WXL_VAR(findObject); WXL_VAR(findCoords.x); WXL_VAR(findCoords.y);
// if the cursorobject is a cmd, we need to find the first
// printable object:
while(cursorObject != end()
@@ -370,32 +380,32 @@ wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const &findCoords)
long descent = 0l; long width, height;
tobj = (wxLayoutObjectText *)*i;
String str = tobj->GetText();
VAR(m_CursorPosition.x); VAR(cursor.x);
WXL_VAR(m_CursorPosition.x); WXL_VAR(cursor.x);
str = str.substr(0, cursorOffset);
VAR(str);
WXL_VAR(str);
dc.GetTextExtent(Str(str), &width,&height, &descent);
VAR(height);
VAR(width); VAR(descent);
if(width < 1) width = 1;
dc.DrawLine(position.x+width,
position.y+(baseLineSkip-height),
position.x+width, position.y+baseLineSkip);
WXL_VAR(height);
WXL_VAR(width);
WXL_VAR(descent);
cursorPosition = wxPoint(position.x+width,
position.y+(baseLineSkip-height));
cursorSize = wxPoint(1, height);
//dc.DrawLine(position.x+width,
// position.y+(baseLineSkip-height),
// position.x+width, position.y+baseLineSkip);
}
else
{
if(type == WXLO_TYPE_LINEBREAK)
dc.DrawLine(0, position.y+baseLineSkip, 0, position.y+2*baseLineSkip);
else
//dc.DrawLine(0, position.y+baseLineSkip, 0, position.y+2*baseLineSkip);
{
if(size.x == 0)
{
if(size.y == 0)
dc.DrawLine(position.x, position.y, position.x, position.y+baseLineSkip);
else
dc.DrawLine(position.x, position.y, position.x, position.y+size.y);
cursorPosition = wxPoint(0, position.y);
cursorSize = wxPoint(1,baseLineSkip);
}
else
dc.DrawRectangle(position.x, position.y, size.x, size.y);
{
cursorPosition = wxPoint(position.x, position.y);
cursorSize = wxPoint(size.x > 0 ? size.x : 1,size.y > 0 ? size.y : baseLineSkip);
}
}
}
@@ -462,6 +472,12 @@ wxLayoutList::Draw(wxDC &dc, bool findObject, wxPoint const &findCoords)
i++;
}
dc.EndDoc();
// draw the cursor
if(m_Editable)
{
dc.DrawRectangle(cursorPosition.x, cursorPosition.y,
cursorSize.x, cursorSize.y);
}
m_MaxY = position.y;
return foundObject;
}
@@ -512,50 +528,80 @@ wxLayoutList::Debug(void)
// don't change this, I know how to optimise this and will do it real
// soon (KB)
/*
* FindObjectCursor:
* Finds the object belonging to a given cursor position cpos and
* returns an iterator to that object and stores the relative cursor
* position in offset.
*
* For linebreaks, the offset can be 0=before or 1=after.
*
* If the cpos coordinates don't exist, they are modified.
*/
wxLayoutObjectList::iterator
wxLayoutList::FindObjectCursor(wxPoint const &cpos, CoordType *offset)
wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset)
{
wxPoint cursor = wxPoint(0,0); // runs along the objects
wxPoint object = wxPoint(0,0); // runs along the objects
CoordType width;
wxLayoutObjectList::iterator i;
#ifdef WXLAYOUT_DEBUG
cerr << "Looking for object at " << cpos.x << ',' << cpos.y <<
cerr << "Looking for object at " << cpos->x << ',' << cpos->y <<
endl;
#endif
for(i = begin(); i != end() && cursor.y <= cpos.y; i++)
for(i = begin(); i != end() && object.y <= cpos->y; i++)
{
width = 0;
if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
width = (**i).CountPositions();
if(cpos->y == object.y) // a possible candidate
{
if(cpos.y == cursor.y && i != begin())
if((**i).GetType() ==WXLO_TYPE_LINEBREAK)
{
--i;
if(offset) *offset = i != end() ? (*i)->CountPositions() : 0;
if(cpos->x == object.x)
{
*offset = 0;
return i;
}
cursor.x = 0; cursor.y ++;
*offset=1;
cpos->x = object.x;
return i;
}
else
cursor.x += (width = (*i)->CountPositions());
if(cursor.y == cpos.y && (cursor.x > cpos.x ||
((*i)->GetType() != WXLO_TYPE_CMD && cursor.x == cpos.x))
) // found it ?
if(cpos->x >= object.x && cpos->x <= object.x+width) // overlap
{
if(offset)
*offset = cpos.x-(cursor.x-width); // 0==cursor before
// the object
if(offset) *offset = cpos->x-object.x;
#ifdef WXLAYOUT_DEBUG
cerr << " found object at " << cursor.x-width << ',' <<
cursor.y << ", type:" << _t[(*i)->GetType()] <<endl;
cerr << " found object at " << object.x << ',' <<
object.y << ", type:" << _t[(*i)->GetType()] <<endl;
#endif
return i;
}
}
// no overlap, increment coordinates
object.x += width;
if((**i).GetType() == WXLO_TYPE_LINEBREAK)
{
object.x = 0;
object.y++;
}
}
#ifdef WXLAYOUT_DEBUG
cerr << " not found" << endl;
#endif
return end(); // not found
// return last object, coordinates of that one:
i = tail();
if(i == end())
return i;
if((**i).GetType()==WXLO_TYPE_LINEBREAK)
{
if(offset)
*offset = (cpos.x > object.x) : 1 : 0;
return i;
}
cpos->x = object.x; // would be the coordinate of next object
cpos->y = object.y;
cpos->x += width; // last object's width
if(*offset) *offset = cpos->x-object.x
return i; // not found
}
wxLayoutObjectList::iterator
@@ -563,7 +609,7 @@ wxLayoutList::FindCurrentObject(CoordType *offset)
{
wxLayoutObjectList::iterator obj = end();
obj = FindObjectCursor(m_CursorPosition, offset);
obj = FindObjectCursor(&m_CursorPosition, offset);
if(obj == end()) // not ideal yet
{
obj = tail();
@@ -665,68 +711,71 @@ wxLayoutList::MoveCursor(int dx, int dy)
void
wxLayoutList::Delete(CoordType count)
{
TRACE(Delete);
WXL_TRACE(Delete);
if(!m_Editable)
return;
VAR(count);
WXL_VAR(count);
CoordType offs, len;
CoordType offs;
wxLayoutObjectList::iterator i;
do
{
i = FindCurrentObject(&offs);
startover: // ugly, but easiest way to do it
if(i == end())
return;
#ifdef WXLAYOUT_DEBUG
cerr << "trying to delete: " << _t[(*i)->GetType()] << endl;
#endif
return; // we cannot delete anything more
/* Here we need to treat linebreaks differently.
If offs==0 we are before the linebreak, otherwise behind. */
if((*i)->GetType() == WXLO_TYPE_LINEBREAK)
{
if(offs == 0)
{
m_MaxLine--;
if((*i)->GetType() == WXLO_TYPE_TEXT)
erase(i);
count--;
continue; // we're done
}
else // delete the object behind the linebreak
{
i++; // we increment and continue as normal
offs=0;
goto startover;
}
}
else if((*i)->GetType() == WXLO_TYPE_TEXT)
{
wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
len = tobj->CountPositions();
CoordType len = tobj->CountPositions();
// If we find the end of a text object, this means that we
// have to delete from the object following it.
if(offs == len)
if(len == offs)
{
i++;
if(i != end() && (*i)->GetType() == WXLO_TYPE_TEXT)
{
offs = 0; // delete from begin of next string
tobj = (wxLayoutObjectText *)*i;
len = tobj->CountPositions();
offs = 0;
goto startover;
}
else
{
erase(i);
return;
}
}
if(len <= count) // delete this object
else if(len <= count) // delete this object
{
count -= len;
erase(i);
continue;
}
else
{
len = count;
VAR(offs); VAR(len);
tobj->GetText().erase(offs,len);
return; // we are done
}
}
else // delete the object
else // all other objects: delete the object
{
len = (*i)->CountPositions();
CoordType len = (*i)->CountPositions();
erase(i); // after this, i is the iterator for the following object
if(count > len)
count -= len;
else
count = 0;
count = count > len ? count -= len : 0;
}
}
while(count && i != end());
@@ -739,29 +788,30 @@ wxLayoutList::Insert(wxLayoutObjectBase *obj)
CoordType offs;
wxLayoutObjectList::iterator i = FindCurrentObject(&offs);
TRACE(Insert(obj));
WXL_TRACE(Insert(obj));
if(i == end())
push_back(obj);
else
{
else if(offs == 0)
insert(i,obj);
// do we have to split a text object?
if((*i)->GetType() == WXLO_TYPE_TEXT && offs != 0 && offs != (*i)->CountPositions())
else if((*i)->GetType() == WXLO_TYPE_TEXT && offs != (*i)->CountPositions())
{
wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
#ifdef WXLAYOUT_DEBUG
cerr << "text: '" << tobj->GetText() << "'" << endl;
VAR(offs);
WXL_VAR(offs);
#endif
String left = tobj->GetText().substr(0,offs); // get part before cursor
VAR(left);
WXL_VAR(left);
tobj->GetText() = tobj->GetText().substr(offs,(*i)->CountPositions()-offs); // keeps the right half
VAR(tobj->GetText());
WXL_VAR(tobj->GetText());
insert(i,obj);
insert(i,new wxLayoutObjectText(left)); // inserts before
}
else
{
// all other cases, append after object:
wxLayoutObjectList::iterator j = i; // we want to apend after this object
j++;
if(j != end())
@@ -769,7 +819,7 @@ wxLayoutList::Insert(wxLayoutObjectBase *obj)
else
push_back(obj);
}
}
m_CursorPosition.x += obj->CountPositions();
if(obj->GetType() == WXLO_TYPE_LINEBREAK)
m_MaxLine++;
@@ -779,7 +829,7 @@ void
wxLayoutList::Insert(String const &text)
{
wxLayoutObjectText *tobj = NULL;
TRACE(Insert(text));
WXL_TRACE(Insert(text));
if(! m_Editable)
return;
@@ -789,7 +839,7 @@ wxLayoutList::Insert(String const &text)
if(i != end() && (*i)->GetType() == WXLO_TYPE_TEXT)
{ // insert into an existing text object:
TRACE(inserting into existing object);
WXL_TRACE(inserting into existing object);
tobj = (wxLayoutObjectText *)*i ;
wxASSERT(tobj);
tobj->GetText().insert(offs,text);
@@ -798,7 +848,7 @@ wxLayoutList::Insert(String const &text)
{
wxLayoutObjectList::iterator j = i;
j--;
TRACE(checking previous object);
WXL_TRACE(checking previous object);
if(0 && j != end() && (*j)->GetType() == WXLO_TYPE_TEXT)
{
tobj = (wxLayoutObjectText *)*i;
@@ -807,7 +857,7 @@ wxLayoutList::Insert(String const &text)
}
else // insert a new text object
{
TRACE(creating new object);
WXL_TRACE(creating new object);
Insert(new wxLayoutObjectText(text)); //FIXME not too optimal, slow
return; // position gets incremented in Insert(obj)
}

View File

@@ -14,7 +14,7 @@
#include "kbList.h"
#include <wx/wx.h>
#include "wx/wx.h"
// skip the following defines if embedded in M application
#ifdef M_BASEDIR
@@ -47,8 +47,9 @@ typedef long CoordType;
class wxLayoutList;
class wxLayoutObjectBase;
/// Define a list type of wxLayoutObjectBase pointers.
KBLIST_DEFINE(wxLayoutObjectList, wxLayoutObjectBase);
class wxDC;
class wxColour;
class wxFont;
/** The base class defining the interface to each object which can be
part of the layout. Each object needs to draw itself and calculate
@@ -99,6 +100,10 @@ private:
void * m_UserData;
};
/// Define a list type of wxLayoutObjectBase pointers.
KBLIST_DEFINE(wxLayoutObjectList, wxLayoutObjectBase);
/// object for text block
class wxLayoutObjectText : public wxLayoutObjectBase
{
@@ -138,8 +143,9 @@ public:
bool draw = true);
virtual wxPoint GetSize(CoordType *baseLine) const;
wxLayoutObjectIcon(wxIcon *icon);
private:
wxIcon * m_Icon;
wxIcon *m_Icon;
};
/// for export to html:
@@ -294,7 +300,7 @@ protected:
bool m_Editable;
/// find the object to the cursor position and returns the offset
/// in there
wxLayoutObjectList::iterator FindObjectCursor(wxPoint const &cpos, CoordType *offset = NULL);
wxLayoutObjectList::iterator FindObjectCursor(wxPoint *cpos, CoordType *offset = NULL);
};

View File

@@ -24,22 +24,17 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
: wxScrolledWindow(parent)
{
m_ScrollbarsSet = false;
m_EventId = 0;
m_EventId = -1;
}
void
wxLayoutWindow::OnMouse(wxMouseEvent& event)
{
if(m_EventId == 0) // nothing to do
if(m_EventId == -1) // nothing to do
return;
// this is unintuitive
wxClientDC dc(this);
PrepareDC( dc );
m_FindPos.x = dc.DeviceToLogicalX( event.GetX() );
m_FindPos.y = dc.DeviceToLogicalY( event.GetY() );
m_FindPos.x = event.GetX();
m_FindPos.y = event.GetY();
m_FoundObject = NULL;
#ifdef WXLAYOUT_DEBUG
@@ -48,7 +43,7 @@ wxLayoutWindow::OnMouse(wxMouseEvent& event)
Refresh();
if(m_FoundObject)
{
if(m_EventId)
if(m_EventId != -1)
{
wxCommandEvent commandEvent(wxEVENT_TYPE_MENU_COMMAND, m_EventId);
commandEvent.SetEventObject( this );
@@ -138,7 +133,7 @@ wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)w) // or: OnDraw(wxDC& dc
wxPaintDC dc( this ); // only when used as OnPaint for OnDraw we
PrepareDC( dc ); // can skip the first two lines
if(m_EventId) // look for keyclicks
if(m_EventId != -1) // look for keyclicks
m_FoundObject = m_llist.Draw(dc,true,m_FindPos);
else
m_llist.Draw(dc);

View File

@@ -12,16 +12,12 @@
# pragma interface "wxlwindow.h"
#endif
#include <wx/wx.h>
#ifndef USE_PCH
# include <wx/wx.h>
#endif
#include "wxllist.h"
#define BROKEN_COMPILER
#ifdef BROKEN_COMPILER
# define virtual
#endif
class wxLayoutWindow : public wxScrolledWindow
{
public:
@@ -38,18 +34,24 @@ public:
SetBackgroundColour( *GetLayoutList().GetDefaults()->GetBGColour());
}
//virtual void OnDraw(wxDC &dc);
// callbacks
// NB: these functions are used as event handlers and must not be virtual
//void OnDraw(wxDC &dc);
void OnPaint(wxPaintEvent &WXUNUSED(event));
virtual void OnMouse(wxMouseEvent& event);
virtual void OnChar(wxKeyEvent& event);
void OnMouse(wxMouseEvent& event);
void OnChar(wxKeyEvent& event);
#ifdef __WXMSW__
virtual long MSWGetDlgCode();
#endif //MSW
void UpdateScrollbars(void);
void Print(void);
void Erase(void)
{ m_llist.Clear(); Clear(); }
void Erase(void) { m_llist.Clear(); Clear(); }
void SetEventId(int id) { m_EventId = id; }
wxPoint const &GetClickPosition(void) const { return
m_ClickPosition; }
virtual ~wxLayoutWindow() {} ;
wxPoint const &GetClickPosition(void) const { return m_ClickPosition; }
virtual ~wxLayoutWindow() {}
private:
/// for sending events
wxWindow *m_Parent;
@@ -62,11 +64,8 @@ private:
wxPoint m_FindPos;
wxLayoutObjectBase *m_FoundObject;
wxPoint m_ClickPosition;
DECLARE_EVENT_TABLE()
};
#ifdef BROKEN_COMPILER
#undef virtual
#endif
#endif