


## answer-dialog-factory.pkg
#
# When the user enters an incorrect answer, the application
# uses this dialog to display the problem plus the correct answer.
# Compiled by:
# src/lib/x-kit/tut/arithmetic-game/arithmetic-game-app.libstipulate
include threadkit; # threadkit is from src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg #
package xg = xgeometry; # xgeometry is from src/lib/std/2d/xgeometry.pkg #
package xc = xclient; # xclient is from src/lib/x-kit/xclient/xclient.pkg #
package cv = canvas; # canvas is from src/lib/x-kit/widget/leaf/canvas.pkg package wg = widget; # widget is from src/lib/x-kit/widget/basic/widget.pkg package lw = line_of_widgets; # line_of_widgets is from src/lib/x-kit/widget/layout/line-of-widgets.pkg package sz = size_preference_wrapper; # size_preference_wrapper is from src/lib/x-kit/widget/wrapper/size-preference-wrapper.pkg package pb = pushbuttons; # pushbuttons is from src/lib/x-kit/widget/leaf/pushbuttons.pkg package tw = topwindow; # topwindow is from src/lib/x-kit/widget/wrapper/size-preference-wrapper.pkgherein
package answer_dialog_factory: Answer_Dialog_Factory { # Answer_Dialog_Factory is from src/lib/x-kit/tut/arithmetic-game/answer-dialog-factory.api debug_tracing = logger::make_logtree_leaf
{ parent => xlogger::xkit_logging,
name => "answer::debug_tracing",
default => FALSE # Change to TRUE or call (log::enable debug_tracing) to enable logging in this file.
};
log_if = logger::log_if;
Answer_Dialog_Factory
=
ANSWER_DIALOG_FACTORY
{
root_window: wg::Root_Window,
font: xc::Font,
lead: Int
};
fun make_answer_dialog_factory
( root_window: wg::Root_Window,
fontname: String
)
=
{ font = xc::open_font (wg::xsession_of root_window) fontname;
my { ascent, descent }
=
xc::font_high font;
lead = ascent + descent;
ANSWER_DIALOG_FACTORY { root_window, font, lead };
};
fun make_answer_dialog_widget
( answer_dialog_factory,
operand1, # First value user is to add/subtract/multiply.
operand2, # Second value user is to add/subtract/multipy.
op_string, # Is user to add, subtract or multiply?
correct_answer # Answer user should have gotten from above.
)
=
{ answer_dialog_factory
->
ANSWER_DIALOG_FACTORY { root_window, font, lead }; # 'lead' is the font height (i.e., ascent + descent).
s1 = int::to_string operand1;
s2 = op_string + " " + (int::to_string operand2);
s3 = int::to_string correct_answer;
l1 = xc::text_width font s1;
l2 = xc::text_width font s2;
l3 = xc::text_width font s3;
wd = int::max (l1, int::max (l2, l3));
s1y = lead;
s2y = s1y + lead;
liney = s2y + 4;
s3y = liney + lead;
size_preferences
=
{ col_preference => wg::tight_preference wd,
row_preference => wg::tight_preference (s3y + 4)
};
(cv::make_canvas root_window size_preferences)
->
(canvas, size, kidplug);
(xc::ignore_mouse_and_keyboard kidplug)
->
xc::KIDPLUG { from_other', ... };
black = xc::black;
pen = xc::make_pen [ xc::p::FOREGROUND (xc::rgb8_from_rgb black) ];
fun main size
=
other_loop size
where
drawable = cv::drawable_of canvas;
draw_transparent_string = xc::draw_transparent_string drawable pen font;
draw_line = xc::draw_lines drawable pen;
fun draw (xg::SIZE { wide, high } )
=
{ log_if debug_tracing 0 .{ "in draw"; };
xc::clear_drawable drawable;
draw_transparent_string (xg::POINT { col=>wide-l1, row=>s1y }, s1);
draw_transparent_string (xg::POINT { col=>wide-l2, row=>s2y }, s2);
draw_line
[ xg::POINT { col=>0, row=>liney },
xg::POINT { col=>wide, row=>liney }
];
draw_transparent_string (xg::POINT { col=>wide-l3, row=>s3y }, s3);
};
fun other_loop size
=
case (xc::envelope_contents (block_until_mailop_fires from_other'))
#
xc::ETC_REDRAW _
=>
{ draw size;
other_loop size;
};
xc::ETC_RESIZE (xg::BOX { wide, high, ... } )
=>
other_loop (xg::SIZE { wide, high } );
_ =>
other_loop size;
esac;
end;
make_thread "answer dialogue redrawer" .{ main size; };
cv::as_widget canvas;
};
# Display correct answer to
# user in a pop-up dialog window:
#
fun make_answer_dialog
( answer_dialog_factory,
window,
operand1, # First value user is to add/subtract/multiply.
operand2, # Second value user is to add/subtract/multipy.
op_string, # Is user to add, subtract or multiply?
correct_answer # Answer user should have gotten from above.
)
=
{ log_if debug_tracing 0 .{ "in show_answer_dialog"; };
answer_dialog_factory
->
ANSWER_DIALOG_FACTORY { root_window, ... };
# We close our pop-up window when
# either of these gets set:
#
close_dialog_oneshot = make_oneshot_maildrop (); # calculation_pane will set this at start of new game.
cancel_button_oneshot = make_oneshot_maildrop (); # Our "Cancel" button will set this when clicked.
answer_dialog_widget
=
make_answer_dialog_widget (answer_dialog_factory, operand1, operand2, op_string, correct_answer);
log_if debug_tracing 0 .{ "Created answer_dialog."; };
cancel_button
=
pb::make_text_pushbutton_with_click_callback root_window
{
click_callback => .{ put_in_oneshot (cancel_button_oneshot, ()); },
rounded => TRUE,
label => "Cancel",
#
foreground => NULL,
background => NULL
};
pane_layout
=
lw::as_widget
(lw::make_line_of_widgets root_window
( lw::VT_CENTER
[
lw::HZ_CENTER
[
lw::SPACER { min_size=>3, ideal_size=>3, max_size=>NULL },
lw::WIDGET answer_dialog_widget,
lw::SPACER { min_size=>3, ideal_size=>3, max_size=>NULL }
],
lw::SPACER { min_size=>5, ideal_size=>5, max_size=>NULL },
lw::HZ_CENTER
[
lw::SPACER { min_size=>5, ideal_size=>5, max_size=>NULL },
lw::WIDGET (sz::make_tight_size_preference_wrapper (pb::as_widget cancel_button)),
lw::SPACER { min_size=>5, ideal_size=>5, max_size=>NULL }
],
lw::SPACER { min_size=>5, ideal_size=>5, max_size=>NULL }
]
) );
log_if debug_tracing 0 .{ "Created layout."; };
topwindow = tw::make_transient_topwindow
window
( pane_layout,
NULL,
{ window_name => THE "Answer Dialog",
icon_name => THE "Answer Dialog"
}
);
log_if debug_tracing 0 .{ "Created topwindow."; };
# Close our window if user clicks our "Cancel" button
# or if calculation_pane tells us to (at start of new game):
#
fun close_window_on_command ()
=
{ log_if debug_tracing 0 .{ "close_window_on_command await event"; };
#
do_one_mailop (map take_from_oneshot' [close_dialog_oneshot, cancel_button_oneshot]);
log_if debug_tracing 0 .{ "close_window_on_command got event; destroy topwindow"; };
tw::destroy topwindow;
};
log_if debug_tracing 0 .{ "spawn close_window_on_command"; };
make_thread "answer dialog closer" close_window_on_command;
log_if debug_tracing 0 .{ "Initializing topwindow..."; };
tw::start topwindow;
log_if debug_tracing 0 .{ "return iv"; };
close_dialog_oneshot; # Caller can close our window by setting this to void.
};
};
end;


