Virtual window gets a preprocessing handler

This commit is contained in:
Markus Gans 2017-01-15 19:48:27 +01:00
parent 49e36e5203
commit 5cb7b77f4e
17 changed files with 191 additions and 117 deletions

View File

@ -1,3 +1,7 @@
2017-01-15 Markus Gans <guru.mail@muenster.de>
* Virtual window gets a preprocessing handler. This allows
a preprocessing method to be called before the vterm is updated.
2017-01-07 Markus Gans <guru.mail@muenster.de> 2017-01-07 Markus Gans <guru.mail@muenster.de>
* Add scrollTo and scrollBy methods to FScrollView * Add scrollTo and scrollBy methods to FScrollView

View File

@ -8,8 +8,8 @@ case "$1" in
./configure --prefix="$PREFIX" CPPFLAGS="-DDEBUG" CXXFLAGS="-g -O0 -DDEBUG -W -Wall -pedantic" ./configure --prefix="$PREFIX" CPPFLAGS="-DDEBUG" CXXFLAGS="-g -O0 -DDEBUG -W -Wall -pedantic"
;; ;;
"--fulldebug"|"fulldebug") "--/fulldebug"|"fulldebug")
./configure --prefix="$PREFIX" CPPFLAGS="-DDEBUG" CXXFLAGS="-g -O0 -DDEBUG -W -Wall -Weffc++ -pedantic -pedantic-errors -Wextra -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winit-self -Winvalid-pch -Wlong-long -Wmissing-braces -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpadded -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wstack-protector -Wstrict-aliasing -Wstrict-aliasing=3 -Wswitch -Wswitch-enum -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wvariadic-macros -Wvolatile-register-var -Wwrite-strings -Wsign-promo -Woverloaded-virtual -Wstrict-null-sentinel -fext-numeric-literals -Wreorder -Wnoexcept -Wnarrowing -Wliteral-suffix -Wctor-dtor-privacy" ./configure --prefix="$PREFIX" CPPFLAGS="-DDEBUG" CXXFLAGS="-g -O0 -DDEBUG -W -Wall -Weffc++ -pedantic -pedantic-errors -Wextra -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wimport -Winit-self -Winvalid-pch -Wlong-long -Wmissing-braces -Wmissing-field-initializers -Wmissing-format-attribute -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpadded -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -fstack-protector -Wstrict-aliasing -Wstrict-aliasing=3 -Wswitch -Wswitch-enum -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wvariadic-macros -Wvolatile-register-var -Wwrite-strings -Wsign-promo -Woverloaded-virtual -Wstrict-null-sentinel -fext-numeric-literals -Wreorder -Wnoexcept -Wnarrowing -Wliteral-suffix -Wctor-dtor-privacy"
;; ;;
"--profile"|"profile") "--profile"|"profile")

View File

@ -50,6 +50,10 @@ void FScrollView::setScrollWidth (int width)
FPoint no_shadow(0,0); FPoint no_shadow(0,0);
scroll_size.setWidth (width); scroll_size.setWidth (width);
resizeArea (scroll_size, no_shadow, viewport); resizeArea (scroll_size, no_shadow, viewport);
setPreprocessingHandler
(
_PREPROC_HANDLER (this, &FScrollView::copy2area)
);
child_print_area = viewport; child_print_area = viewport;
} }
@ -73,6 +77,10 @@ void FScrollView::setScrollHeight (int height)
FPoint no_shadow(0,0); FPoint no_shadow(0,0);
scroll_size.setHeight (height); scroll_size.setHeight (height);
resizeArea (scroll_size, no_shadow, viewport); resizeArea (scroll_size, no_shadow, viewport);
setPreprocessingHandler
(
_PREPROC_HANDLER (this, &FScrollView::copy2area)
);
child_print_area = viewport; child_print_area = viewport;
} }
@ -99,6 +107,10 @@ void FScrollView::setScrollSize (int width, int height)
FPoint no_shadow(0,0); FPoint no_shadow(0,0);
scroll_size.setSize (width, height); scroll_size.setSize (width, height);
resizeArea (scroll_size, no_shadow, viewport); resizeArea (scroll_size, no_shadow, viewport);
setPreprocessingHandler
(
_PREPROC_HANDLER (this, &FScrollView::copy2area)
);
child_print_area = viewport; child_print_area = viewport;
} }
@ -124,8 +136,8 @@ void FScrollView::setX (int x, bool adjust)
if ( viewport ) if ( viewport )
{ {
viewport->x_offset = scroll_size.getX(); viewport->offset_top = scroll_size.getX();
viewport->y_offset = scroll_size.getY(); viewport->offset_left = scroll_size.getY();
} }
} }
} }
@ -141,8 +153,8 @@ void FScrollView::setY (int y, bool adjust)
if ( viewport ) if ( viewport )
{ {
viewport->x_offset = scroll_size.getX(); viewport->offset_top = scroll_size.getX();
viewport->y_offset = scroll_size.getY(); viewport->offset_left = scroll_size.getY();
} }
} }
} }
@ -158,8 +170,8 @@ void FScrollView::setPos (int x, int y, bool adjust)
{ {
if ( viewport ) if ( viewport )
{ {
viewport->x_offset = scroll_size.getX(); viewport->offset_top = scroll_size.getX();
viewport->y_offset = scroll_size.getY(); viewport->offset_left = scroll_size.getY();
} }
} }
} }
@ -210,8 +222,8 @@ void FScrollView::setGeometry (int x, int y, int w, int h, bool adjust)
} }
else if ( ! adjust && viewport ) else if ( ! adjust && viewport )
{ {
viewport->x_offset = scroll_size.getX(); viewport->offset_top = scroll_size.getX();
viewport->y_offset = scroll_size.getY(); viewport->offset_left = scroll_size.getY();
} }
} }
@ -303,7 +315,7 @@ void FScrollView::draw()
if ( FWidget* p = getParentWidget() ) if ( FWidget* p = getParentWidget() )
setColor (p->getForegroundColor(), p->getBackgroundColor()); setColor (p->getForegroundColor(), p->getBackgroundColor());
else else
setColor (wc.dialog_fg, wc.dialog_bg); setColor();
if ( isNewFont() ) if ( isNewFont() )
drawBorder (1, 1, getWidth() - 1, getHeight()); drawBorder (1, 1, getWidth() - 1, getHeight());
@ -496,8 +508,8 @@ void FScrollView::adjustSize()
if ( viewport ) if ( viewport )
{ {
viewport->x_offset = scroll_size.getX(); viewport->offset_top = scroll_size.getX();
viewport->y_offset = scroll_size.getY(); viewport->offset_left = scroll_size.getY();
} }
hbar->setMaximum (getScrollWidth() - getClientWidth()); hbar->setMaximum (getScrollWidth() - getClientWidth());
@ -536,8 +548,8 @@ void FScrollView::copy2area()
if ( ! viewport->has_changes ) if ( ! viewport->has_changes )
return; return;
ax = getTermX() - print_area->x_offset; ax = getTermX() - print_area->offset_top;
ay = getTermY() - print_area->y_offset; ay = getTermY() - print_area->offset_left;
dx = scroll_offset.getX(); dx = scroll_offset.getX();
dy = scroll_offset.getY(); dy = scroll_offset.getY();
y_end = getClientHeight(); y_end = getClientHeight();
@ -567,6 +579,9 @@ void FScrollView::copy2area()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void FScrollView::init() void FScrollView::init()
{ {
setForegroundColor (wc.dialog_fg);
setBackgroundColor (wc.dialog_bg);
vbar = new FScrollbar(fc::vertical, this); vbar = new FScrollbar(fc::vertical, this);
vbar->setMinimum(0); vbar->setMinimum(0);
vbar->setValue(0); vbar->setValue(0);
@ -582,6 +597,7 @@ void FScrollView::init()
"change-value", "change-value",
_METHOD_CALLBACK (this, &FScrollView::cb_VBarChange) _METHOD_CALLBACK (this, &FScrollView::cb_VBarChange)
); );
hbar->addCallback hbar->addCallback
( (
"change-value", "change-value",
@ -597,6 +613,10 @@ void FScrollView::init()
FPoint no_shadow(0,0); FPoint no_shadow(0,0);
scroll_size.setRect (1, 1, getClientWidth(), getClientHeight()); scroll_size.setRect (1, 1, getClientWidth(), getClientHeight());
createArea (scroll_size, no_shadow, viewport); createArea (scroll_size, no_shadow, viewport);
setPreprocessingHandler
(
_PREPROC_HANDLER (this, &FScrollView::copy2area)
);
if ( viewport ) if ( viewport )
child_print_area = viewport; child_print_area = viewport;

View File

@ -617,6 +617,7 @@ void FTextView::init()
"change-value", "change-value",
_METHOD_CALLBACK (this, &FTextView::cb_VBarChange) _METHOD_CALLBACK (this, &FTextView::cb_VBarChange)
); );
hbar->addCallback hbar->addCallback
( (
"change-value", "change-value",

View File

@ -64,8 +64,8 @@ FPoint FVTerm::getPrintCursor()
term_area* win = getPrintArea(); term_area* win = getPrintArea();
if ( win ) if ( win )
return FPoint ( win->x_offset + win->cursor_x return FPoint ( win->offset_top + win->cursor_x
, win->y_offset + win->cursor_y ); , win->offset_left + win->cursor_y );
return FPoint(0,0); return FPoint(0,0);
} }
@ -150,8 +150,22 @@ void FVTerm::setPrintCursor (register int x, register int y)
if ( win ) if ( win )
{ {
win->cursor_x = x - win->x_offset; win->cursor_x = x - win->offset_top;
win->cursor_y = y - win->y_offset; win->cursor_y = y - win->offset_left;
}
}
//----------------------------------------------------------------------
void FVTerm::setPreprocessingHandler ( FVTerm* instance
, FPreprocessingHandler handler )
{
if ( ! print_area )
FVTerm::getPrintArea();
if ( print_area )
{
print_area->pre_proc_instance = instance;
print_area->pre_proc = handler;
} }
} }
@ -668,7 +682,7 @@ void FVTerm::createArea ( const FRect& r
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void FVTerm::createArea ( int x_offset, int y_offset void FVTerm::createArea ( int offset_top, int offset_left
, int width, int height , int width, int height
, int rsw, int bsh , int rsw, int bsh
, term_area*& area ) , term_area*& area )
@ -677,8 +691,8 @@ void FVTerm::createArea ( int x_offset, int y_offset
area = new term_area; area = new term_area;
area->x_offset = 0; area->offset_top = 0;
area->y_offset = 0; area->offset_left = 0;
area->width = -1; area->width = -1;
area->height = -1; area->height = -1;
area->right_shadow = 0; area->right_shadow = 0;
@ -693,8 +707,10 @@ void FVTerm::createArea ( int x_offset, int y_offset
area->text = 0; area->text = 0;
area->visible = false; area->visible = false;
area->widget = static_cast<FWidget*>(this); area->widget = static_cast<FWidget*>(this);
area->pre_proc_instance = 0;
area->pre_proc = 0;
resizeArea (x_offset, y_offset, width, height, rsw, bsh, area); resizeArea (offset_top, offset_left, width, height, rsw, bsh, area);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -712,7 +728,7 @@ void FVTerm::resizeArea ( const FRect& r
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void FVTerm::resizeArea ( int x_offset, int y_offset void FVTerm::resizeArea ( int offset_top, int offset_left
, int width, int height , int width, int height
, int rsw, int bsh , int rsw, int bsh
, term_area* area ) , term_area* area )
@ -747,8 +763,8 @@ void FVTerm::resizeArea ( int x_offset, int y_offset
else else
return; return;
area->x_offset = x_offset; area->offset_top = offset_top;
area->y_offset = y_offset; area->offset_left = offset_left;
area->width = width; area->width = width;
area->height = height; area->height = height;
area->right_shadow = rsw; area->right_shadow = rsw;
@ -875,8 +891,8 @@ void FVTerm::restoreVTerm (int x, int y, int w, int h)
if ( ! win->visible ) if ( ! win->visible )
continue; continue;
int win_x = win->x_offset; int win_x = win->offset_top;
int win_y = win->y_offset; int win_y = win->offset_left;
FRect geometry ( win_x FRect geometry ( win_x
, win_y , win_y
, win->width + win->right_shadow , win->width + win->right_shadow
@ -974,8 +990,8 @@ FVTerm::covered_state FVTerm::isCovered ( int x, int y
if ( ! win->visible ) if ( ! win->visible )
continue; continue;
int win_x = win->x_offset; int win_x = win->offset_top;
int win_y = win->y_offset; int win_y = win->offset_left;
FRect geometry ( win_x FRect geometry ( win_x
, win_y , win_y
, win->width + win->right_shadow , win->width + win->right_shadow
@ -1041,6 +1057,13 @@ void FVTerm::updateVTerm()
updateVTerm(win); updateVTerm(win);
win->has_changes = false; win->has_changes = false;
} }
else if ( win->pre_proc_instance
&& win->pre_proc_instance->child_print_area
&& win->pre_proc_instance->child_print_area->has_changes )
{
updateVTerm(win);
win->pre_proc_instance->child_print_area->has_changes = false;
}
} }
} }
@ -1059,8 +1082,12 @@ void FVTerm::updateVTerm (term_area* area)
if ( ! area->visible ) if ( ! area->visible )
return; return;
ax = area->x_offset; // Call preprocessing handler
ay = area->y_offset; if ( area->pre_proc_instance && area->pre_proc )
(area->pre_proc_instance->*area->pre_proc)();
ax = area->offset_top;
ay = area->offset_left;
aw = area->width; aw = area->width;
ah = area->height; ah = area->height;
rsh = area->right_shadow; rsh = area->right_shadow;
@ -1237,8 +1264,8 @@ bool FVTerm::updateVTermCursor (term_area* area)
{ {
int cx, cy, ax, ay, x, y; int cx, cy, ax, ay, x, y;
// area offset // area offset
ax = area->x_offset; ax = area->offset_top;
ay = area->y_offset; ay = area->offset_left;
// area cursor position // area cursor position
cx = area->input_cursor_x; cx = area->input_cursor_x;
cy = area->input_cursor_y; cy = area->input_cursor_y;
@ -1365,8 +1392,8 @@ void FVTerm::getArea (int x, int y, int w, int h, term_area* area)
if ( ! area ) if ( ! area )
return; return;
dx = x - area->x_offset + 1; dx = x - area->offset_top + 1;
dy = y - area->y_offset + 1; dy = y - area->offset_left + 1;
if ( x < 0 || y < 0 ) if ( x < 0 || y < 0 )
return; return;
@ -1810,8 +1837,8 @@ FVTerm::char_data FVTerm::getCharacter ( character_type char_type
if ( ! win->visible ) if ( ! win->visible )
continue; continue;
int win_x = win->x_offset; int win_x = win->offset_top;
int win_y = win->y_offset; int win_y = win->offset_left;
FRect geometry ( win_x FRect geometry ( win_x
, win_y , win_y
, win->width + win->right_shadow , win->width + win->right_shadow
@ -1897,8 +1924,9 @@ void FVTerm::processTerminalUpdate()
// Retains terminal updates if there are unprocessed inputs // Retains terminal updates if there are unprocessed inputs
static const int max_skip = 8; static const int max_skip = 8;
if ( terminal_update_pending ) if ( ! terminal_update_pending )
{ return;
if ( ! unprocessedInput() ) if ( ! unprocessedInput() )
{ {
updateTerminal(); updateTerminal();
@ -1916,7 +1944,6 @@ void FVTerm::processTerminalUpdate()
else else
skipped_terminal_update++; skipped_terminal_update++;
} }
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void FVTerm::startTerminalUpdate() void FVTerm::startTerminalUpdate()

View File

@ -29,10 +29,14 @@
#include "fterm.h" #include "fterm.h"
#include <sstream> // std::stringstream #include <sstream> // std::stringstream
// Preprocessing handler macro
#define _PREPROC_HANDLER(i,h) \
reinterpret_cast<FVTerm*>((i)) \
, reinterpret_cast<FVTerm::FPreprocessingHandler>((h))
// class forward declaration // class forward declaration
class FWidget; class FWidget;
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// class FVTerm // class FVTerm
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -46,29 +50,32 @@ class FVTerm : public FObject, public FTerm
// Typedefs and Enumeration // Typedefs and Enumeration
typedef struct typedef struct
{ {
uInt xmin; uInt xmin; // X-position with the first change
uInt xmax; uInt xmax; // X-position with the last change
uInt trans_count; uInt trans_count; // Number of transparent characters
} line_changes; } line_changes;
typedef FOptiAttr::char_data char_data; typedef FOptiAttr::char_data char_data;
typedef void (FVTerm::*FPreprocessingHandler)();
typedef struct typedef struct
{ {
int x_offset; int offset_top; // Distance from top of the terminal
int y_offset; int offset_left; // Distance from left terminal side
int width; int width; // Window width
int height; int height; // Window height
int right_shadow; int right_shadow; // Right window shadow
int bottom_shadow; int bottom_shadow; // Bottom window shadow
int cursor_x; int cursor_x; // X-position for the next write operation
int cursor_y; int cursor_y; // Y-position for the next write operation
int input_cursor_x; int input_cursor_x; // X-position input cursor
int input_cursor_y; int input_cursor_y; // Y-position input cursor
int input_cursor_visible; FWidget* widget; // Widget that owns this term_area
FWidget* widget; FVTerm* pre_proc_instance;
FPreprocessingHandler pre_proc;
line_changes* changes; line_changes* changes;
char_data* text; char_data* text; // Text data for the output
bool input_cursor_visible;
bool has_changes; bool has_changes;
bool visible; bool visible;
} term_area; } term_area;
@ -170,6 +177,9 @@ class FVTerm : public FObject, public FTerm
static bool setInheritBackground(); static bool setInheritBackground();
static bool unsetInheritBackground(); static bool unsetInheritBackground();
void setPreprocessingHandler ( FVTerm*
, FPreprocessingHandler );
// Inquiries // Inquiries
static bool isCursorHidden(); static bool isCursorHidden();
static bool isBold(); static bool isBold();

View File

@ -879,6 +879,7 @@ void FWidget::delCallback (FWidget* cb_instance)
inline void FWidget::delCallbacks() inline void FWidget::delCallbacks()
{ {
// delete all callbacks from this widget // delete all callbacks from this widget
member_callback_objects.clear(); // member function pointer member_callback_objects.clear(); // member function pointer
callback_objects.clear(); // function pointer callback_objects.clear(); // function pointer
} }

View File

@ -307,7 +307,7 @@ void FWindow::setX (int x, bool adjust)
FWidget::setX (x, adjust); FWidget::setX (x, adjust);
if ( vwin ) if ( vwin )
vwin->x_offset = getTermX() - 1; vwin->offset_top = getTermX() - 1;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -319,7 +319,7 @@ void FWindow::setY (int y, bool adjust)
FWidget::setY (y, adjust); FWidget::setY (y, adjust);
if ( vwin ) if ( vwin )
vwin->y_offset = getTermY() - 1; vwin->offset_left = getTermY() - 1;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -332,8 +332,8 @@ void FWindow::setPos (int x, int y, bool adjust)
if ( vwin ) if ( vwin )
{ {
vwin->x_offset = getTermX() - 1; vwin->offset_top = getTermX() - 1;
vwin->y_offset = getTermY() - 1; vwin->offset_left = getTermY() - 1;
} }
} }
@ -405,10 +405,10 @@ void FWindow::setGeometry (int x, int y, int w, int h, bool adjust)
else else
{ {
if ( getX() != old_x ) if ( getX() != old_x )
vwin->x_offset = getTermX() - 1; vwin->offset_top = getTermX() - 1;
if ( getY() != old_y ) if ( getY() != old_y )
vwin->y_offset = getTermY() - 1; vwin->offset_left = getTermY() - 1;
} }
} }
@ -419,8 +419,8 @@ void FWindow::move (int dx, int dy)
if ( vwin ) if ( vwin )
{ {
vwin->x_offset = getTermX() - 1; vwin->offset_top = getTermX() - 1;
vwin->y_offset = getTermY() - 1; vwin->offset_left = getTermY() - 1;
} }
} }
@ -787,10 +787,10 @@ void FWindow::adjustSize()
else if ( vwin ) else if ( vwin )
{ {
if ( getX() != old_x ) if ( getX() != old_x )
vwin->x_offset = getTermX() - 1; vwin->offset_top = getTermX() - 1;
if ( getY() != old_y ) if ( getY() != old_y )
vwin->y_offset = getTermY() - 1; vwin->offset_left = getTermY() - 1;
} }
} }

View File

@ -351,58 +351,69 @@ MyDialog::MyDialog (FWidget* parent)
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_view) _METHOD_CALLBACK (this, &MyDialog::cb_view)
); );
Quit->addCallback Quit->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_exitApp) _METHOD_CALLBACK (this, &MyDialog::cb_exitApp)
); );
Cut->addCallback Cut->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_cutClipboard) _METHOD_CALLBACK (this, &MyDialog::cb_cutClipboard)
); );
Copy->addCallback Copy->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_copyClipboard) _METHOD_CALLBACK (this, &MyDialog::cb_copyClipboard)
); );
Paste->addCallback Paste->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_pasteClipboard) _METHOD_CALLBACK (this, &MyDialog::cb_pasteClipboard)
); );
Clear->addCallback Clear->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_clearInput) _METHOD_CALLBACK (this, &MyDialog::cb_clearInput)
); );
Env->addCallback Env->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_terminfo) _METHOD_CALLBACK (this, &MyDialog::cb_terminfo)
); );
Drive->addCallback Drive->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_drives) _METHOD_CALLBACK (this, &MyDialog::cb_drives)
); );
Help->addCallback Help->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_about) _METHOD_CALLBACK (this, &MyDialog::cb_about)
); );
File1->addCallback File1->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_view), _METHOD_CALLBACK (this, &MyDialog::cb_view),
dynamic_cast<FWidget::data_ptr>(File1) dynamic_cast<FWidget::data_ptr>(File1)
); );
File2->addCallback File2->addCallback
( (
"clicked", "clicked",
_METHOD_CALLBACK (this, &MyDialog::cb_view), _METHOD_CALLBACK (this, &MyDialog::cb_view),
dynamic_cast<FWidget::data_ptr>(File2) dynamic_cast<FWidget::data_ptr>(File2)
); );
File3->addCallback File3->addCallback
( (
"clicked", "clicked",