Fixes and more functionality.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1929 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
77c630ca85
commit
6ba4e8aceb
@ -5,9 +5,14 @@ BUGS
|
||||
- dmalloc shows duplicate deletion after merging two lines and
|
||||
deleting the second half
|
||||
|
||||
- printout page calculation still a bit wrong
|
||||
- word wrap for objects with lots of non-space needs to search in positive
|
||||
direction if begin of first object is reached
|
||||
|
||||
TODO
|
||||
=====================================================================
|
||||
|
||||
- replacement of llist in window
|
||||
- undo
|
||||
- Selections
|
||||
- More optimisations
|
||||
|
||||
|
@ -33,7 +33,7 @@ IMPLEMENT_APP(MyApp)
|
||||
enum ids{ ID_ADD_SAMPLE = 1, ID_CLEAR, ID_PRINT,
|
||||
ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS,
|
||||
ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_PS,
|
||||
ID_WRAP, ID_NOWRAP,
|
||||
ID_WRAP, ID_NOWRAP, ID_PASTE,
|
||||
ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT, ID_TEST };
|
||||
|
||||
|
||||
@ -63,10 +63,9 @@ MyFrame::MyFrame(void) :
|
||||
|
||||
SetStatusText( "wxLayout by Karsten Ballüder." );
|
||||
|
||||
wxMenuBar *menu_bar = new wxMenuBar();
|
||||
|
||||
wxMenu *file_menu = new wxMenu;
|
||||
file_menu->Append( ID_CLEAR, "Clear");
|
||||
file_menu->Append( ID_ADD_SAMPLE, "Example");
|
||||
|
||||
file_menu->Append(ID_PRINT, "&Print...", "Print");
|
||||
file_menu->Append(ID_PRINT_SETUP, "Print &Setup...","Setup printer properties");
|
||||
file_menu->Append(ID_PAGE_SETUP, "Page Set&up...", "Page setup");
|
||||
@ -78,18 +77,22 @@ MyFrame::MyFrame(void) :
|
||||
file_menu->Append(ID_PAGE_SETUP_PS, "Page Setup PostScript...", "Page setup (PostScript)");
|
||||
file_menu->Append(ID_PREVIEW_PS, "Print Preview PostScript", "Preview (PostScript)");
|
||||
#endif
|
||||
file_menu->AppendSeparator();
|
||||
file_menu->Append(ID_WRAP, "Wrap mode", "Activate wrapping at pixel 200.");
|
||||
file_menu->Append(ID_NOWRAP, "No-wrap mode", "Deactivate wrapping.");
|
||||
|
||||
file_menu->AppendSeparator();
|
||||
file_menu->Append( ID_TEXT, "Export Text");
|
||||
file_menu->Append( ID_HTML, "Export HTML");
|
||||
file_menu->Append( ID_QUIT, "Exit");
|
||||
|
||||
wxMenuBar *menu_bar = new wxMenuBar();
|
||||
menu_bar->Append(file_menu, "File" );
|
||||
|
||||
wxMenu *edit_menu = new wxMenu;
|
||||
edit_menu->Append( ID_CLEAR, "Clear");
|
||||
edit_menu->Append( ID_ADD_SAMPLE, "Example");
|
||||
edit_menu->AppendSeparator();
|
||||
edit_menu->Append(ID_WRAP, "Wrap mode", "Activate wrapping at pixel 200.");
|
||||
edit_menu->Append(ID_NOWRAP, "No-wrap mode", "Deactivate wrapping.");
|
||||
edit_menu->AppendSeparator();
|
||||
edit_menu->Append(ID_PASTE, "Paste", "Paste text from clipboard.");
|
||||
menu_bar->Append(edit_menu, "Edit" );
|
||||
|
||||
#ifndef __WXMSW__
|
||||
menu_bar->Show( TRUE );
|
||||
#endif // MSW
|
||||
@ -222,6 +225,9 @@ void MyFrame::OnCommand( wxCommandEvent &event )
|
||||
case ID_CLICK:
|
||||
cerr << "Received click event." << endl;
|
||||
break;
|
||||
case ID_PASTE:
|
||||
m_lwin->Paste();
|
||||
break;
|
||||
case ID_HTML:
|
||||
{
|
||||
wxLayoutExportObject *export;
|
||||
|
@ -72,6 +72,7 @@ bool operator !=(wxPoint const &p1, wxPoint const &p2)
|
||||
return p1.x != p2.x || p1.y != p2.y;
|
||||
}
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
|
||||
wxLayoutObjectText
|
||||
@ -87,6 +88,17 @@ wxLayoutObjectText::wxLayoutObjectText(const wxString &txt)
|
||||
m_Bottom = 0;
|
||||
}
|
||||
|
||||
wxLayoutObject *
|
||||
wxLayoutObjectText::Copy(void)
|
||||
{
|
||||
wxLayoutObjectText *obj = new wxLayoutObjectText(m_Text);
|
||||
obj->m_Width = m_Width;
|
||||
obj->m_Height = m_Height;
|
||||
obj->m_Top = m_Top;
|
||||
obj->m_Bottom = m_Bottom;
|
||||
obj->SetUserData(m_UserData);
|
||||
return obj;
|
||||
}
|
||||
|
||||
wxPoint
|
||||
wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const
|
||||
@ -157,6 +169,15 @@ wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap const &icon)
|
||||
m_Icon = new wxBitmap(icon);
|
||||
}
|
||||
|
||||
wxLayoutObject *
|
||||
wxLayoutObjectIcon::Copy(void)
|
||||
{
|
||||
wxLayoutObjectIcon *obj = new wxLayoutObjectIcon(new
|
||||
wxBitmap(*m_Icon));
|
||||
obj->SetUserData(m_UserData);
|
||||
return obj;
|
||||
}
|
||||
|
||||
wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap *icon)
|
||||
{
|
||||
m_Icon = icon;
|
||||
@ -199,6 +220,20 @@ wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
|
||||
m_ColourBG = bg;
|
||||
}
|
||||
|
||||
wxLayoutObject *
|
||||
wxLayoutObjectCmd::Copy(void)
|
||||
{
|
||||
wxLayoutStyleInfo si;
|
||||
GetStyle(&si);
|
||||
|
||||
wxLayoutObjectCmd *obj = new wxLayoutObjectCmd(
|
||||
si.size, si.family, si.style, si.weight, si.underline,
|
||||
m_ColourFG, m_ColourBG);
|
||||
obj->SetUserData(m_UserData);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
wxLayoutObjectCmd::~wxLayoutObjectCmd()
|
||||
{
|
||||
delete m_font;
|
||||
@ -787,15 +822,38 @@ wxLayoutLine::GetWrapPosition(CoordType column)
|
||||
column--;
|
||||
}
|
||||
}while(offset != -1);
|
||||
i--; // move on to previous object
|
||||
}
|
||||
else
|
||||
{
|
||||
column -= (**i).GetLength();
|
||||
// This is both "else" and what has to be done after checking
|
||||
// all positions of the text object:
|
||||
i--;
|
||||
offset = (**i).GetLength();
|
||||
i--;
|
||||
}
|
||||
if( i != NULLIT)
|
||||
offset = (**i).GetLength();
|
||||
}while(i != NULLIT);
|
||||
return -1;
|
||||
/* If we reached the begin of the list and have more than one
|
||||
object, that one is longer than the margin, so break behind
|
||||
it. */
|
||||
CoordType pos = 0;
|
||||
i = m_ObjectList.begin();
|
||||
while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
|
||||
{
|
||||
pos += (**i).GetLength();
|
||||
i++;
|
||||
}
|
||||
if(i == NULLIT) return -1; //why should this happen?
|
||||
pos += (**i).GetLength();
|
||||
i++;
|
||||
while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
|
||||
{
|
||||
pos += (**i).GetLength();
|
||||
i++;
|
||||
}
|
||||
if(i == NULLIT) return -1; //this is possible, if there is only one text object
|
||||
// now we are at the second text object:
|
||||
pos -= (**i).GetLength();
|
||||
return pos; // in front of it
|
||||
}
|
||||
|
||||
|
||||
@ -809,7 +867,7 @@ wxLayoutList::wxLayoutList()
|
||||
{
|
||||
m_DefaultSetting = NULL;
|
||||
m_FirstLine = NULL;
|
||||
InternalClear();
|
||||
Clear();
|
||||
}
|
||||
|
||||
wxLayoutList::~wxLayoutList()
|
||||
@ -818,17 +876,11 @@ wxLayoutList::~wxLayoutList()
|
||||
}
|
||||
|
||||
void
|
||||
wxLayoutList::InternalClear(void)
|
||||
wxLayoutList::Empty(void)
|
||||
{
|
||||
while(m_FirstLine)
|
||||
m_FirstLine = m_FirstLine->DeleteLine(false);
|
||||
|
||||
if(m_DefaultSetting)
|
||||
{
|
||||
delete m_DefaultSetting;
|
||||
m_DefaultSetting = NULL;
|
||||
}
|
||||
|
||||
m_CursorPos = wxPoint(0,0);
|
||||
m_CursorScreenPos = wxPoint(0,0);
|
||||
m_CursorSize = wxPoint(0,0);
|
||||
@ -836,6 +888,18 @@ wxLayoutList::InternalClear(void)
|
||||
m_CursorLine = m_FirstLine;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
wxLayoutList::InternalClear(void)
|
||||
{
|
||||
Empty();
|
||||
if(m_DefaultSetting)
|
||||
{
|
||||
delete m_DefaultSetting;
|
||||
m_DefaultSetting = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wxLayoutList::SetFont(int family, int size, int style, int weight,
|
||||
int underline, wxColour const *fg,
|
||||
@ -906,7 +970,7 @@ wxLayoutList::MoveCursorTo(wxPoint const &p)
|
||||
{
|
||||
wxLayoutLine *line = m_FirstLine;
|
||||
while(line && line->GetLineNumber() != p.y)
|
||||
;
|
||||
line = line->GetNextLine();
|
||||
if(line && line->GetLineNumber() == p.y) // found it
|
||||
{
|
||||
m_CursorPos.y = p.y;
|
||||
|
@ -83,10 +83,22 @@ class wxFont;
|
||||
class wxLayoutObject
|
||||
{
|
||||
public:
|
||||
/// This structure can be used to contain data associated with the object.
|
||||
/** This structure can be used to contain data associated with the
|
||||
object.
|
||||
It is refcounted, so the caller has to do a DecRef() on it
|
||||
instead of a delete.
|
||||
*/
|
||||
struct UserData
|
||||
{
|
||||
virtual ~UserData() { }
|
||||
UserData() { m_refcount = 1; }
|
||||
void IncRef(void) { m_refcount++; }
|
||||
void DecRef(void) { m_refcount--; if(m_refcount == 0) delete this;}
|
||||
private:
|
||||
int m_refcount;
|
||||
protected:
|
||||
virtual ~UserData() { wxASSERT(m_refcount == 0); }
|
||||
/// prevents gcc from generating stupid warnings
|
||||
friend class dummy_UserData;
|
||||
};
|
||||
|
||||
/// return the type of this object
|
||||
@ -125,7 +137,7 @@ public:
|
||||
/// constructor
|
||||
wxLayoutObject() { m_UserData = NULL; }
|
||||
/// delete the user data
|
||||
virtual ~wxLayoutObject() { if(m_UserData) delete m_UserData; }
|
||||
virtual ~wxLayoutObject() { if(m_UserData) m_UserData->DecRef(); }
|
||||
|
||||
#ifdef WXLAYOUT_DEBUG
|
||||
virtual void Debug(void);
|
||||
@ -134,10 +146,20 @@ public:
|
||||
/** Tells the object about some user data. This data is associated
|
||||
with the object and will be deleted at destruction time.
|
||||
*/
|
||||
void SetUserData(UserData *data) { m_UserData = data; }
|
||||
/** Return the user data. */
|
||||
void * GetUserData(void) const { return m_UserData; }
|
||||
void SetUserData(UserData *data)
|
||||
{
|
||||
if(m_UserData)
|
||||
m_UserData->DecRef();
|
||||
m_UserData = data;
|
||||
m_UserData->IncRef();
|
||||
}
|
||||
|
||||
/** Return the user data. */
|
||||
void * GetUserData(void) const { if(m_UserData) m_UserData->IncRef(); return m_UserData; }
|
||||
|
||||
/** Makes a copy of this object.
|
||||
*/
|
||||
virtual wxLayoutObject *Copy(void) = 0;
|
||||
private:
|
||||
/// optional data for application's use
|
||||
UserData *m_UserData;
|
||||
@ -192,7 +214,9 @@ public:
|
||||
// for editing:
|
||||
wxString & GetText(void) { return m_Text; }
|
||||
void SetText(wxString const &text) { m_Text = text; }
|
||||
|
||||
/** Makes a copy of this object.
|
||||
*/
|
||||
virtual wxLayoutObject *Copy(void);
|
||||
private:
|
||||
wxString m_Text;
|
||||
/// size of the box containing text
|
||||
@ -230,7 +254,11 @@ public:
|
||||
virtual wxPoint GetSize(CoordType * top, CoordType *bottom) const;
|
||||
/// Return just the width of the object on the screen.
|
||||
virtual CoordType GetWidth(void) const { return m_Icon->GetWidth(); }
|
||||
|
||||
// return a pointer to the icon
|
||||
wxBitmap *GetIcon(void) const { return m_Icon; }
|
||||
/** Makes a copy of this object.
|
||||
*/
|
||||
virtual wxLayoutObject *Copy(void);
|
||||
private:
|
||||
wxBitmap *m_Icon;
|
||||
};
|
||||
@ -269,6 +297,9 @@ public:
|
||||
void GetStyle(wxLayoutStyleInfo *si) const;
|
||||
/// return the background colour for setting colour of window
|
||||
wxColour const *GetBGColour(void) const { return m_ColourBG; }
|
||||
/** Makes a copy of this object.
|
||||
*/
|
||||
virtual wxLayoutObject *Copy(void);
|
||||
private:
|
||||
/// the font to use
|
||||
wxFont *m_font;
|
||||
@ -539,7 +570,9 @@ public:
|
||||
int underline=0,
|
||||
char const *fg="black",
|
||||
char const *bg="white");
|
||||
|
||||
/// Empty: clear the list but leave font settings.
|
||||
void Empty(void);
|
||||
|
||||
/**@name Cursor Management */
|
||||
//@{
|
||||
/** Set new cursor position.
|
||||
|
@ -32,7 +32,7 @@ inline static bool IsEndOfLine(const char *p, int mode)
|
||||
(((*p == '\r') && (*(p + 1) == '\n'))||(*p == '\n'));
|
||||
}
|
||||
|
||||
void wxLayoutImportText(wxLayoutList &list, wxString const &str, int withflag)
|
||||
void wxLayoutImportText(wxLayoutList *list, wxString const &str, int withflag)
|
||||
{
|
||||
char * cptr = (char *)str.c_str(); // string gets changed only temporarily
|
||||
const char * begin = cptr;
|
||||
@ -45,7 +45,7 @@ void wxLayoutImportText(wxLayoutList &list, wxString const &str, int withflag)
|
||||
cptr++;
|
||||
backup = *cptr;
|
||||
*cptr = '\0';
|
||||
list.Insert(begin);
|
||||
list->Insert(begin);
|
||||
*cptr = backup;
|
||||
|
||||
// check if it's the end of this line
|
||||
@ -54,7 +54,7 @@ void wxLayoutImportText(wxLayoutList &list, wxString const &str, int withflag)
|
||||
// if it was "\r\n", skip the following '\n'
|
||||
if ( *cptr == '\r' )
|
||||
cptr++;
|
||||
list.LineBreak();
|
||||
list->LineBreak();
|
||||
}
|
||||
else if(backup == '\0') // reached end of string
|
||||
break;
|
||||
@ -158,7 +158,7 @@ wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
|
||||
{
|
||||
wxASSERT(status);
|
||||
wxLayoutExportObject * export;
|
||||
|
||||
|
||||
if(status->m_iterator == NULLIT) // end of line
|
||||
{
|
||||
if(!status->m_line || status->m_line->GetNextLine() == NULL) // reached end of list
|
||||
@ -168,6 +168,14 @@ wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
|
||||
status->m_line = status->m_line->GetNextLine();
|
||||
status->m_iterator = status->m_line->GetFirstObject();
|
||||
export = new wxLayoutExportObject();;
|
||||
if( (mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_OBJECTS) // simple case
|
||||
{
|
||||
export->type = WXLO_EXPORT_OBJECT;
|
||||
export->content.object = *status->m_iterator;
|
||||
status->m_iterator++;
|
||||
return export;
|
||||
}
|
||||
//else: text object:
|
||||
export->type = ((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML)
|
||||
? WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT;
|
||||
if((mode & WXLO_EXPORT_WITH_CRLF) == WXLO_EXPORT_WITH_CRLF)
|
||||
|
@ -68,14 +68,14 @@ struct wxLayoutExportStatus
|
||||
|
||||
#ifdef OS_WIN
|
||||
/// import text into a wxLayoutList (including linefeeds):
|
||||
void wxLayoutImportText(wxLayoutList &list, wxString const &str,
|
||||
void wxLayoutImportText(wxLayoutList *list, wxString const &str,
|
||||
int withflag = WXLO_EXPORT_WITH_CRLF);
|
||||
|
||||
wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
|
||||
int mode = WXLO_EXPORT_AS_TEXT|WXLO_EXPORT_WITH_CRLF);
|
||||
#else
|
||||
/// import text into a wxLayoutList (including linefeeds):
|
||||
void wxLayoutImportText(wxLayoutList &list, wxString const &str,
|
||||
void wxLayoutImportText(wxLayoutList *list, wxString const &str,
|
||||
int withflag = WXLO_EXPORT_WITH_LF_ONLY);
|
||||
|
||||
/// export text in a given format FIXME-MT: not thread safe, uses static variable
|
||||
|
@ -27,10 +27,11 @@
|
||||
# undef StartDoc
|
||||
# endif
|
||||
# include "wxlwindow.h"
|
||||
# include "wxlparser.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <wx/clipbrd.h>
|
||||
|
||||
#define WXLO_XOFFSET 4
|
||||
#define WXLO_YOFFSET 4
|
||||
@ -266,11 +267,23 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
|
||||
void
|
||||
wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc)
|
||||
{
|
||||
DoPaint();
|
||||
m_ScrollToCursor = false;
|
||||
InternalPaint();
|
||||
}
|
||||
|
||||
void
|
||||
wxLayoutWindow::DoPaint(bool scrollToCursor)
|
||||
{
|
||||
m_ScrollToCursor = scrollToCursor;
|
||||
#ifdef __WXGTK__
|
||||
InternalPaint();
|
||||
#else
|
||||
Refresh();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
wxLayoutWindow::InternalPaint(void)
|
||||
{
|
||||
wxPaintDC dc( this );
|
||||
PrepareDC( dc );
|
||||
@ -301,7 +314,7 @@ wxLayoutWindow::DoPaint(bool scrollToCursor)
|
||||
/* Make sure that the scrollbars are at a position so that the
|
||||
cursor is visible if we are editing. */
|
||||
/** Scroll so that cursor is visible! */
|
||||
if(IsEditable() && scrollToCursor)
|
||||
if(IsEditable() && m_ScrollToCursor)
|
||||
{
|
||||
wxPoint cc = m_llist->GetCursorScreenPos();
|
||||
if(cc.x < x0 || cc.y < y0
|
||||
@ -366,6 +379,22 @@ wxLayoutWindow::ResizeScrollbars(bool exact)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wxLayoutWindow::Paste(void)
|
||||
{
|
||||
// Read some text
|
||||
if (wxTheClipboard->Open())
|
||||
{
|
||||
wxTextDataObject data;
|
||||
if (wxTheClipboard->IsSupported(wxDF_TEXT))
|
||||
{
|
||||
wxTheClipboard->GetData(&data);
|
||||
wxLayoutImportText( m_llist, data.GetText());
|
||||
}
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
wxMenu *
|
||||
wxLayoutWindow::MakeFormatMenu()
|
||||
|
@ -16,7 +16,7 @@
|
||||
# include <wx/wx.h>
|
||||
#endif
|
||||
|
||||
#include "wxllist.h"
|
||||
#include "wxllist.h"
|
||||
|
||||
#ifndef WXLOWIN_MENU_FIRST
|
||||
# define WXLOWIN_MENU_FIRST 12000
|
||||
@ -76,7 +76,9 @@ public:
|
||||
void SetEditable(bool toggle) { m_Editable = toggle; }
|
||||
/// Query whether list can be edited by user.
|
||||
bool IsEditable(void) const { return m_Editable; }
|
||||
|
||||
/// Pastes text from clipboard.
|
||||
void Paste(void);
|
||||
|
||||
//@}
|
||||
|
||||
void EnablePopup(bool enable = true) { m_DoPopupMenu = enable; }
|
||||
@ -87,6 +89,8 @@ public:
|
||||
void SetWrapMargin(CoordType margin) { m_WrapMargin = margin; }
|
||||
|
||||
/** Redraws the window.
|
||||
Internally, this stores the parameter and calls a refresh on
|
||||
wxMSW, draws directly on wxGTK.
|
||||
@param scrollToCursor if true, scroll the window so that the
|
||||
cursor becomes visible
|
||||
*/
|
||||
@ -121,16 +125,17 @@ public:
|
||||
|
||||
/// Creates a wxMenu for use as a format popup.
|
||||
static wxMenu * MakeFormatMenu(void);
|
||||
/// Set dirty flag.
|
||||
void SetDirty(void) { m_Dirty = true; }
|
||||
protected:
|
||||
/**@name Dirty flag handling for optimisations. */
|
||||
//@{
|
||||
/// Set dirty flag.
|
||||
void SetDirty(void) { m_Dirty = true; }
|
||||
/// Query whether window needs redrawing.
|
||||
bool IsDirty(void) const { return m_Dirty; }
|
||||
/// Reset dirty flag.
|
||||
void ResetDirty(void) { m_Dirty = false; }
|
||||
//@}
|
||||
/// Redraws the window, used by DoPaint() or OnPaint().
|
||||
void InternalPaint(void);
|
||||
protected:
|
||||
/// generic function for mouse events processing
|
||||
void OnMouse(int eventId, wxMouseEvent& event);
|
||||
@ -145,6 +150,8 @@ protected:
|
||||
bool m_HaveFocus;
|
||||
/// do we handle clicks of the right mouse button?
|
||||
bool m_DoPopupMenu;
|
||||
/// Should InternalPaint() scroll to cursor.
|
||||
bool m_ScrollToCursor;
|
||||
/// the menu
|
||||
wxMenu * m_PopupMenu;
|
||||
/// for derived classes, set when mouse is clicked
|
||||
|
Loading…
Reference in New Issue
Block a user