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:
Karsten Ballüder
1999-03-14 21:22:10 +00:00
parent 77c630ca85
commit 6ba4e8aceb
8 changed files with 200 additions and 48 deletions

View File

@@ -5,9 +5,14 @@ BUGS
- dmalloc shows duplicate deletion after merging two lines and - dmalloc shows duplicate deletion after merging two lines and
deleting the second half 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 TODO
===================================================================== =====================================================================
- replacement of llist in window
- undo
- Selections - Selections
- More optimisations - More optimisations

View File

@@ -33,7 +33,7 @@ IMPLEMENT_APP(MyApp)
enum ids{ ID_ADD_SAMPLE = 1, ID_CLEAR, ID_PRINT, enum ids{ ID_ADD_SAMPLE = 1, ID_CLEAR, ID_PRINT,
ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS, ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS,
ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_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 }; 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<6C>der." ); SetStatusText( "wxLayout by Karsten Ball<6C>der." );
wxMenu *file_menu = new wxMenu; wxMenuBar *menu_bar = new wxMenuBar();
file_menu->Append( ID_CLEAR, "Clear");
file_menu->Append( ID_ADD_SAMPLE, "Example");
wxMenu *file_menu = new wxMenu;
file_menu->Append(ID_PRINT, "&Print...", "Print"); file_menu->Append(ID_PRINT, "&Print...", "Print");
file_menu->Append(ID_PRINT_SETUP, "Print &Setup...","Setup printer properties"); file_menu->Append(ID_PRINT_SETUP, "Print &Setup...","Setup printer properties");
file_menu->Append(ID_PAGE_SETUP, "Page Set&up...", "Page setup"); 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_PAGE_SETUP_PS, "Page Setup PostScript...", "Page setup (PostScript)");
file_menu->Append(ID_PREVIEW_PS, "Print Preview PostScript", "Preview (PostScript)"); file_menu->Append(ID_PREVIEW_PS, "Print Preview PostScript", "Preview (PostScript)");
#endif #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->AppendSeparator();
file_menu->Append( ID_TEXT, "Export Text"); file_menu->Append( ID_TEXT, "Export Text");
file_menu->Append( ID_HTML, "Export HTML"); file_menu->Append( ID_HTML, "Export HTML");
file_menu->Append( ID_QUIT, "Exit"); file_menu->Append( ID_QUIT, "Exit");
wxMenuBar *menu_bar = new wxMenuBar();
menu_bar->Append(file_menu, "File" ); 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__ #ifndef __WXMSW__
menu_bar->Show( TRUE ); menu_bar->Show( TRUE );
#endif // MSW #endif // MSW
@@ -222,6 +225,9 @@ void MyFrame::OnCommand( wxCommandEvent &event )
case ID_CLICK: case ID_CLICK:
cerr << "Received click event." << endl; cerr << "Received click event." << endl;
break; break;
case ID_PASTE:
m_lwin->Paste();
break;
case ID_HTML: case ID_HTML:
{ {
wxLayoutExportObject *export; wxLayoutExportObject *export;

View File

@@ -72,6 +72,7 @@ bool operator !=(wxPoint const &p1, wxPoint const &p2)
return p1.x != p2.x || p1.y != p2.y; return p1.x != p2.x || p1.y != p2.y;
} }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wxLayoutObjectText wxLayoutObjectText
@@ -87,6 +88,17 @@ wxLayoutObjectText::wxLayoutObjectText(const wxString &txt)
m_Bottom = 0; 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 wxPoint
wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const
@@ -157,6 +169,15 @@ wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap const &icon)
m_Icon = new wxBitmap(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) wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap *icon)
{ {
m_Icon = icon; m_Icon = icon;
@@ -199,6 +220,20 @@ wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
m_ColourBG = bg; 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() wxLayoutObjectCmd::~wxLayoutObjectCmd()
{ {
delete m_font; delete m_font;
@@ -787,15 +822,38 @@ wxLayoutLine::GetWrapPosition(CoordType column)
column--; column--;
} }
}while(offset != -1); }while(offset != -1);
i--; // move on to previous object
} }
else else
{
column -= (**i).GetLength(); column -= (**i).GetLength();
// This is both "else" and what has to be done after checking
// all positions of the text object:
i--; i--;
}
if( i != NULLIT)
offset = (**i).GetLength(); offset = (**i).GetLength();
}while(i != NULLIT); }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_DefaultSetting = NULL;
m_FirstLine = NULL; m_FirstLine = NULL;
InternalClear(); Clear();
} }
wxLayoutList::~wxLayoutList() wxLayoutList::~wxLayoutList()
@@ -818,17 +876,11 @@ wxLayoutList::~wxLayoutList()
} }
void void
wxLayoutList::InternalClear(void) wxLayoutList::Empty(void)
{ {
while(m_FirstLine) while(m_FirstLine)
m_FirstLine = m_FirstLine->DeleteLine(false); m_FirstLine = m_FirstLine->DeleteLine(false);
if(m_DefaultSetting)
{
delete m_DefaultSetting;
m_DefaultSetting = NULL;
}
m_CursorPos = wxPoint(0,0); m_CursorPos = wxPoint(0,0);
m_CursorScreenPos = wxPoint(0,0); m_CursorScreenPos = wxPoint(0,0);
m_CursorSize = wxPoint(0,0); m_CursorSize = wxPoint(0,0);
@@ -836,6 +888,18 @@ wxLayoutList::InternalClear(void)
m_CursorLine = m_FirstLine; m_CursorLine = m_FirstLine;
} }
void
wxLayoutList::InternalClear(void)
{
Empty();
if(m_DefaultSetting)
{
delete m_DefaultSetting;
m_DefaultSetting = NULL;
}
}
void void
wxLayoutList::SetFont(int family, int size, int style, int weight, wxLayoutList::SetFont(int family, int size, int style, int weight,
int underline, wxColour const *fg, int underline, wxColour const *fg,
@@ -906,7 +970,7 @@ wxLayoutList::MoveCursorTo(wxPoint const &p)
{ {
wxLayoutLine *line = m_FirstLine; wxLayoutLine *line = m_FirstLine;
while(line && line->GetLineNumber() != p.y) while(line && line->GetLineNumber() != p.y)
; line = line->GetNextLine();
if(line && line->GetLineNumber() == p.y) // found it if(line && line->GetLineNumber() == p.y) // found it
{ {
m_CursorPos.y = p.y; m_CursorPos.y = p.y;

View File

@@ -83,10 +83,22 @@ class wxFont;
class wxLayoutObject class wxLayoutObject
{ {
public: 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 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 /// return the type of this object
@@ -125,7 +137,7 @@ public:
/// constructor /// constructor
wxLayoutObject() { m_UserData = NULL; } wxLayoutObject() { m_UserData = NULL; }
/// delete the user data /// delete the user data
virtual ~wxLayoutObject() { if(m_UserData) delete m_UserData; } virtual ~wxLayoutObject() { if(m_UserData) m_UserData->DecRef(); }
#ifdef WXLAYOUT_DEBUG #ifdef WXLAYOUT_DEBUG
virtual void Debug(void); virtual void Debug(void);
@@ -134,10 +146,20 @@ public:
/** Tells the object about some user data. This data is associated /** Tells the object about some user data. This data is associated
with the object and will be deleted at destruction time. with the object and will be deleted at destruction time.
*/ */
void SetUserData(UserData *data) { m_UserData = data; } void SetUserData(UserData *data)
/** Return the user data. */ {
void * GetUserData(void) const { return m_UserData; } 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: private:
/// optional data for application's use /// optional data for application's use
UserData *m_UserData; UserData *m_UserData;
@@ -192,7 +214,9 @@ public:
// for editing: // for editing:
wxString & GetText(void) { return m_Text; } wxString & GetText(void) { return m_Text; }
void SetText(wxString const &text) { m_Text = text; } void SetText(wxString const &text) { m_Text = text; }
/** Makes a copy of this object.
*/
virtual wxLayoutObject *Copy(void);
private: private:
wxString m_Text; wxString m_Text;
/// size of the box containing text /// size of the box containing text
@@ -230,7 +254,11 @@ public:
virtual wxPoint GetSize(CoordType * top, CoordType *bottom) const; virtual wxPoint GetSize(CoordType * top, CoordType *bottom) const;
/// Return just the width of the object on the screen. /// Return just the width of the object on the screen.
virtual CoordType GetWidth(void) const { return m_Icon->GetWidth(); } 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: private:
wxBitmap *m_Icon; wxBitmap *m_Icon;
}; };
@@ -269,6 +297,9 @@ public:
void GetStyle(wxLayoutStyleInfo *si) const; void GetStyle(wxLayoutStyleInfo *si) const;
/// return the background colour for setting colour of window /// return the background colour for setting colour of window
wxColour const *GetBGColour(void) const { return m_ColourBG; } wxColour const *GetBGColour(void) const { return m_ColourBG; }
/** Makes a copy of this object.
*/
virtual wxLayoutObject *Copy(void);
private: private:
/// the font to use /// the font to use
wxFont *m_font; wxFont *m_font;
@@ -539,6 +570,8 @@ public:
int underline=0, int underline=0,
char const *fg="black", char const *fg="black",
char const *bg="white"); char const *bg="white");
/// Empty: clear the list but leave font settings.
void Empty(void);
/**@name Cursor Management */ /**@name Cursor Management */
//@{ //@{

View File

@@ -32,7 +32,7 @@ inline static bool IsEndOfLine(const char *p, int mode)
(((*p == '\r') && (*(p + 1) == '\n'))||(*p == '\n')); (((*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 char * cptr = (char *)str.c_str(); // string gets changed only temporarily
const char * begin = cptr; const char * begin = cptr;
@@ -45,7 +45,7 @@ void wxLayoutImportText(wxLayoutList &list, wxString const &str, int withflag)
cptr++; cptr++;
backup = *cptr; backup = *cptr;
*cptr = '\0'; *cptr = '\0';
list.Insert(begin); list->Insert(begin);
*cptr = backup; *cptr = backup;
// check if it's the end of this line // 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 it was "\r\n", skip the following '\n'
if ( *cptr == '\r' ) if ( *cptr == '\r' )
cptr++; cptr++;
list.LineBreak(); list->LineBreak();
} }
else if(backup == '\0') // reached end of string else if(backup == '\0') // reached end of string
break; break;
@@ -168,6 +168,14 @@ wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
status->m_line = status->m_line->GetNextLine(); status->m_line = status->m_line->GetNextLine();
status->m_iterator = status->m_line->GetFirstObject(); status->m_iterator = status->m_line->GetFirstObject();
export = new wxLayoutExportObject();; 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) export->type = ((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML)
? WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT; ? WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT;
if((mode & WXLO_EXPORT_WITH_CRLF) == WXLO_EXPORT_WITH_CRLF) if((mode & WXLO_EXPORT_WITH_CRLF) == WXLO_EXPORT_WITH_CRLF)

View File

@@ -68,14 +68,14 @@ struct wxLayoutExportStatus
#ifdef OS_WIN #ifdef OS_WIN
/// import text into a wxLayoutList (including linefeeds): /// 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); int withflag = WXLO_EXPORT_WITH_CRLF);
wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status, wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
int mode = WXLO_EXPORT_AS_TEXT|WXLO_EXPORT_WITH_CRLF); int mode = WXLO_EXPORT_AS_TEXT|WXLO_EXPORT_WITH_CRLF);
#else #else
/// import text into a wxLayoutList (including linefeeds): /// 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); int withflag = WXLO_EXPORT_WITH_LF_ONLY);
/// export text in a given format FIXME-MT: not thread safe, uses static variable /// export text in a given format FIXME-MT: not thread safe, uses static variable

View File

@@ -27,10 +27,11 @@
# undef StartDoc # undef StartDoc
# endif # endif
# include "wxlwindow.h" # include "wxlwindow.h"
# include "wxlparser.h"
#endif #endif
#include <ctype.h> #include <ctype.h>
#include <wx/clipbrd.h>
#define WXLO_XOFFSET 4 #define WXLO_XOFFSET 4
#define WXLO_YOFFSET 4 #define WXLO_YOFFSET 4
@@ -266,11 +267,23 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
void void
wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc) wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc)
{ {
DoPaint(); m_ScrollToCursor = false;
InternalPaint();
} }
void void
wxLayoutWindow::DoPaint(bool scrollToCursor) wxLayoutWindow::DoPaint(bool scrollToCursor)
{
m_ScrollToCursor = scrollToCursor;
#ifdef __WXGTK__
InternalPaint();
#else
Refresh();
#endif
}
void
wxLayoutWindow::InternalPaint(void)
{ {
wxPaintDC dc( this ); wxPaintDC dc( this );
PrepareDC( dc ); PrepareDC( dc );
@@ -301,7 +314,7 @@ wxLayoutWindow::DoPaint(bool scrollToCursor)
/* Make sure that the scrollbars are at a position so that the /* Make sure that the scrollbars are at a position so that the
cursor is visible if we are editing. */ cursor is visible if we are editing. */
/** Scroll so that cursor is visible! */ /** Scroll so that cursor is visible! */
if(IsEditable() && scrollToCursor) if(IsEditable() && m_ScrollToCursor)
{ {
wxPoint cc = m_llist->GetCursorScreenPos(); wxPoint cc = m_llist->GetCursorScreenPos();
if(cc.x < x0 || cc.y < y0 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 * wxMenu *
wxLayoutWindow::MakeFormatMenu() wxLayoutWindow::MakeFormatMenu()

View File

@@ -76,6 +76,8 @@ public:
void SetEditable(bool toggle) { m_Editable = toggle; } void SetEditable(bool toggle) { m_Editable = toggle; }
/// Query whether list can be edited by user. /// Query whether list can be edited by user.
bool IsEditable(void) const { return m_Editable; } bool IsEditable(void) const { return m_Editable; }
/// Pastes text from clipboard.
void Paste(void);
//@} //@}
@@ -87,6 +89,8 @@ public:
void SetWrapMargin(CoordType margin) { m_WrapMargin = margin; } void SetWrapMargin(CoordType margin) { m_WrapMargin = margin; }
/** Redraws the window. /** 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 @param scrollToCursor if true, scroll the window so that the
cursor becomes visible cursor becomes visible
*/ */
@@ -121,16 +125,17 @@ public:
/// Creates a wxMenu for use as a format popup. /// Creates a wxMenu for use as a format popup.
static wxMenu * MakeFormatMenu(void); static wxMenu * MakeFormatMenu(void);
/// Set dirty flag.
void SetDirty(void) { m_Dirty = true; }
protected:
/**@name Dirty flag handling for optimisations. */ /**@name Dirty flag handling for optimisations. */
//@{ //@{
/// Set dirty flag.
void SetDirty(void) { m_Dirty = true; }
/// Query whether window needs redrawing. /// Query whether window needs redrawing.
bool IsDirty(void) const { return m_Dirty; } bool IsDirty(void) const { return m_Dirty; }
/// Reset dirty flag. /// Reset dirty flag.
void ResetDirty(void) { m_Dirty = false; } void ResetDirty(void) { m_Dirty = false; }
//@} //@}
/// Redraws the window, used by DoPaint() or OnPaint().
void InternalPaint(void);
protected: protected:
/// generic function for mouse events processing /// generic function for mouse events processing
void OnMouse(int eventId, wxMouseEvent& event); void OnMouse(int eventId, wxMouseEvent& event);
@@ -145,6 +150,8 @@ protected:
bool m_HaveFocus; bool m_HaveFocus;
/// do we handle clicks of the right mouse button? /// do we handle clicks of the right mouse button?
bool m_DoPopupMenu; bool m_DoPopupMenu;
/// Should InternalPaint() scroll to cursor.
bool m_ScrollToCursor;
/// the menu /// the menu
wxMenu * m_PopupMenu; wxMenu * m_PopupMenu;
/// for derived classes, set when mouse is clicked /// for derived classes, set when mouse is clicked