| author | kuncar | 
| Fri, 08 Mar 2013 13:21:06 +0100 | |
| changeset 51375 | d9e62d9c98de | 
| parent 51254 | 5bae6fc0e125 | 
| child 51615 | 072a7249e1ac | 
| permissions | -rw-r--r-- | 
| 50686 | 1  | 
/* Title: Pure/Tools/build_dialog.scala  | 
| 50365 | 2  | 
Author: Makarius  | 
3  | 
||
4  | 
Dialog for session build process.  | 
|
5  | 
*/  | 
|
6  | 
||
7  | 
package isabelle  | 
|
8  | 
||
9  | 
||
| 50378 | 10  | 
import java.awt.{GraphicsEnvironment, Point, Font}
 | 
| 
50379
 
a8b0d3729a69
added keyboard shortcut for button (canonical way to do that?);
 
wenzelm 
parents: 
50378 
diff
changeset
 | 
11  | 
|
| 50365 | 12  | 
import scala.swing.{ScrollPane, Button, CheckBox, FlowPanel,
 | 
| 
51254
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
13  | 
BorderPanel, MainFrame, TextArea, SwingApplication, Component, Label}  | 
| 50365 | 14  | 
import scala.swing.event.ButtonClicked  | 
15  | 
||
16  | 
||
| 
50404
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
17  | 
object Build_Dialog  | 
| 50365 | 18  | 
{
 | 
| 
50404
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
19  | 
def main(args: Array[String]) =  | 
| 50365 | 20  | 
  {
 | 
| 50539 | 21  | 
Platform.init_laf()  | 
| 50365 | 22  | 
    try {
 | 
23  | 
      args.toList match {
 | 
|
| 50369 | 24  | 
case  | 
| 
50403
 
87868964733c
more uniform default logic, using settings, options, args etc.;
 
wenzelm 
parents: 
50381 
diff
changeset
 | 
25  | 
logic_option ::  | 
| 50546 | 26  | 
logic ::  | 
| 50369 | 27  | 
Properties.Value.Boolean(system_mode) ::  | 
| 
50403
 
87868964733c
more uniform default logic, using settings, options, args etc.;
 
wenzelm 
parents: 
50381 
diff
changeset
 | 
28  | 
include_dirs =>  | 
| 
50405
 
366c4a602500
clarified build_dialog: regular up-to-date check (extra cost of approx. 5s startup for HOL);
 
wenzelm 
parents: 
50404 
diff
changeset
 | 
29  | 
val more_dirs = include_dirs.map(s => ((false, Path.explode(s))))  | 
| 
50404
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
30  | 
|
| 
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
31  | 
val options = Options.init()  | 
| 
50403
 
87868964733c
more uniform default logic, using settings, options, args etc.;
 
wenzelm 
parents: 
50381 
diff
changeset
 | 
32  | 
val session =  | 
| 
50404
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
33  | 
Isabelle_System.default_logic(logic,  | 
| 
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
34  | 
if (logic_option != "") options.string(logic_option) else "")  | 
| 
50403
 
87868964733c
more uniform default logic, using settings, options, args etc.;
 
wenzelm 
parents: 
50381 
diff
changeset
 | 
35  | 
|
| 
50532
 
345b25cf2e4f
actually request heap image in initial up-to-date check;
 
wenzelm 
parents: 
50405 
diff
changeset
 | 
36  | 
if (Build.build(Build.Ignore_Progress, options, build_heap = true, no_build = true,  | 
| 
50405
 
366c4a602500
clarified build_dialog: regular up-to-date check (extra cost of approx. 5s startup for HOL);
 
wenzelm 
parents: 
50404 
diff
changeset
 | 
37  | 
more_dirs = more_dirs, sessions = List(session)) == 0) sys.exit(0)  | 
| 
50404
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
38  | 
else  | 
| 
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
39  | 
              Swing_Thread.later {
 | 
| 
50405
 
366c4a602500
clarified build_dialog: regular up-to-date check (extra cost of approx. 5s startup for HOL);
 
wenzelm 
parents: 
50404 
diff
changeset
 | 
40  | 
val top = build_dialog(options, system_mode, more_dirs, session)  | 
| 
50404
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
41  | 
top.pack()  | 
| 
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
42  | 
|
| 
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
43  | 
val point = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint()  | 
| 
50532
 
345b25cf2e4f
actually request heap image in initial up-to-date check;
 
wenzelm 
parents: 
50405 
diff
changeset
 | 
44  | 
top.location =  | 
| 
 
345b25cf2e4f
actually request heap image in initial up-to-date check;
 
wenzelm 
parents: 
50405 
diff
changeset
 | 
45  | 
new Point(point.x - top.size.width / 2, point.y - top.size.height / 2)  | 
| 
50404
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
46  | 
|
| 
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
47  | 
top.visible = true  | 
| 
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
48  | 
}  | 
| 50365 | 49  | 
        case _ => error("Bad arguments:\n" + cat_lines(args))
 | 
50  | 
}  | 
|
51  | 
}  | 
|
52  | 
    catch {
 | 
|
53  | 
case exn: Throwable =>  | 
|
54  | 
Library.error_dialog(null, "Isabelle build failure",  | 
|
55  | 
Library.scrollable_text(Exn.message(exn)))  | 
|
56  | 
sys.exit(2)  | 
|
57  | 
}  | 
|
58  | 
}  | 
|
59  | 
||
60  | 
||
| 50369 | 61  | 
def build_dialog(  | 
| 
50404
 
898cac1dad5e
avoid startup within GUI thread -- it is only required later for dialog;
 
wenzelm 
parents: 
50403 
diff
changeset
 | 
62  | 
options: Options,  | 
| 50369 | 63  | 
system_mode: Boolean,  | 
| 
50405
 
366c4a602500
clarified build_dialog: regular up-to-date check (extra cost of approx. 5s startup for HOL);
 
wenzelm 
parents: 
50404 
diff
changeset
 | 
64  | 
more_dirs: List[(Boolean, Path)],  | 
| 50369 | 65  | 
session: String): MainFrame = new MainFrame  | 
| 50365 | 66  | 
  {
 | 
| 50854 | 67  | 
iconImage = Isabelle_System.get_icon().getImage  | 
68  | 
||
69  | 
||
| 50368 | 70  | 
/* GUI state */  | 
| 50365 | 71  | 
|
| 51253 | 72  | 
@volatile private var is_stopped = false  | 
| 50742 | 73  | 
private var return_code = 2  | 
| 50368 | 74  | 
|
| 50740 | 75  | 
    override def closeOperation { sys.exit(return_code) }
 | 
76  | 
||
| 50368 | 77  | 
|
| 50365 | 78  | 
/* text */  | 
79  | 
||
80  | 
    val text = new TextArea {
 | 
|
| 
50853
 
86389991636e
lower bound to font size for the sake of Mac OS X (cf. 4cd2d090be8f);
 
wenzelm 
parents: 
50852 
diff
changeset
 | 
81  | 
      font = new Font("SansSerif", Font.PLAIN, Library.resolution_scale(10) max 14)
 | 
| 50365 | 82  | 
editable = false  | 
| 
50850
 
4cd2d090be8f
tuned font size, notably for current HD displays;
 
wenzelm 
parents: 
50848 
diff
changeset
 | 
83  | 
columns = 50  | 
| 
 
4cd2d090be8f
tuned font size, notably for current HD displays;
 
wenzelm 
parents: 
50848 
diff
changeset
 | 
84  | 
rows = 20  | 
| 50365 | 85  | 
}  | 
86  | 
||
| 
50852
 
a667ac8c7afe
forced scroll to bottom, for improved cross-platform appearance;
 
wenzelm 
parents: 
50850 
diff
changeset
 | 
87  | 
val scroll_text = new ScrollPane(text)  | 
| 
 
a667ac8c7afe
forced scroll to bottom, for improved cross-platform appearance;
 
wenzelm 
parents: 
50850 
diff
changeset
 | 
88  | 
|
| 50368 | 89  | 
val progress = new Build.Progress  | 
90  | 
    {
 | 
|
| 
50846
 
529e652d389d
more uniform theory progress in build -v and build_dialog;
 
wenzelm 
parents: 
50845 
diff
changeset
 | 
91  | 
override def echo(msg: String): Unit =  | 
| 
50852
 
a667ac8c7afe
forced scroll to bottom, for improved cross-platform appearance;
 
wenzelm 
parents: 
50850 
diff
changeset
 | 
92  | 
        Swing_Thread.later {
 | 
| 
 
a667ac8c7afe
forced scroll to bottom, for improved cross-platform appearance;
 
wenzelm 
parents: 
50850 
diff
changeset
 | 
93  | 
text.append(msg + "\n")  | 
| 
 
a667ac8c7afe
forced scroll to bottom, for improved cross-platform appearance;
 
wenzelm 
parents: 
50850 
diff
changeset
 | 
94  | 
val vertical = scroll_text.peer.getVerticalScrollBar  | 
| 
 
a667ac8c7afe
forced scroll to bottom, for improved cross-platform appearance;
 
wenzelm 
parents: 
50850 
diff
changeset
 | 
95  | 
vertical.setValue(vertical.getMaximum)  | 
| 
 
a667ac8c7afe
forced scroll to bottom, for improved cross-platform appearance;
 
wenzelm 
parents: 
50850 
diff
changeset
 | 
96  | 
}  | 
| 
50846
 
529e652d389d
more uniform theory progress in build -v and build_dialog;
 
wenzelm 
parents: 
50845 
diff
changeset
 | 
97  | 
override def theory(session: String, theory: String): Unit =  | 
| 
 
529e652d389d
more uniform theory progress in build -v and build_dialog;
 
wenzelm 
parents: 
50845 
diff
changeset
 | 
98  | 
echo(session + ": theory " + theory)  | 
| 51253 | 99  | 
override def stopped: Boolean = is_stopped  | 
| 50368 | 100  | 
}  | 
101  | 
||
| 50365 | 102  | 
|
| 
51254
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
103  | 
/* layout panel with dynamic actions */  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
104  | 
|
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
105  | 
val action_panel = new FlowPanel(FlowPanel.Alignment.Center)()  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
106  | 
val layout_panel = new BorderPanel  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
107  | 
layout_panel.layout(scroll_text) = BorderPanel.Position.Center  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
108  | 
layout_panel.layout(action_panel) = BorderPanel.Position.South  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
109  | 
|
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
110  | 
contents = layout_panel  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
111  | 
|
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
112  | 
def set_actions(cs: Component*)  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
113  | 
    {
 | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
114  | 
action_panel.contents.clear  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
115  | 
action_panel.contents ++= cs  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
116  | 
layout_panel.revalidate  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
117  | 
layout_panel.repaint  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
118  | 
}  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
119  | 
|
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
120  | 
|
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
121  | 
/* actions */  | 
| 
50848
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
122  | 
|
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
123  | 
var do_auto_close = true  | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
124  | 
def check_auto_close(): Unit = if (do_auto_close && return_code == 0) sys.exit(return_code)  | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
125  | 
|
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
126  | 
    val auto_close = new CheckBox("Auto close") {
 | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
127  | 
      reactions += {
 | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
128  | 
case ButtonClicked(_) => do_auto_close = this.selected  | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
129  | 
check_auto_close()  | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
130  | 
}  | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
131  | 
}  | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
132  | 
auto_close.selected = do_auto_close  | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
133  | 
auto_close.tooltip = "Automatically close dialog when finished"  | 
| 
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
134  | 
|
| 50365 | 135  | 
|
| 
51254
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
136  | 
    val stop_button = new Button("Stop") {
 | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
137  | 
      reactions += {
 | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
138  | 
case ButtonClicked(_) =>  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
139  | 
is_stopped = true  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
140  | 
          set_actions(new Label("Stopping ..."))
 | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
141  | 
}  | 
| 50376 | 142  | 
}  | 
| 
50930
 
23601c59f347
delay to give users a chance to see what was happening, even with auto_close enabled;
 
wenzelm 
parents: 
50854 
diff
changeset
 | 
143  | 
|
| 
51254
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
144  | 
set_actions(stop_button, auto_close)  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
145  | 
|
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
146  | 
|
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
147  | 
/* exit */  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
148  | 
|
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
149  | 
val delay_exit =  | 
| 
50930
 
23601c59f347
delay to give users a chance to see what was happening, even with auto_close enabled;
 
wenzelm 
parents: 
50854 
diff
changeset
 | 
150  | 
Swing_Thread.delay_first(Time.seconds(1.0))  | 
| 
 
23601c59f347
delay to give users a chance to see what was happening, even with auto_close enabled;
 
wenzelm 
parents: 
50854 
diff
changeset
 | 
151  | 
      {
 | 
| 
 
23601c59f347
delay to give users a chance to see what was happening, even with auto_close enabled;
 
wenzelm 
parents: 
50854 
diff
changeset
 | 
152  | 
check_auto_close()  | 
| 
51254
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
153  | 
val button =  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
154  | 
          new Button(if (return_code == 0) "OK" else "Exit") {
 | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
155  | 
            reactions += { case ButtonClicked(_) => sys.exit(return_code) }
 | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
156  | 
}  | 
| 
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
157  | 
set_actions(button)  | 
| 
50930
 
23601c59f347
delay to give users a chance to see what was happening, even with auto_close enabled;
 
wenzelm 
parents: 
50854 
diff
changeset
 | 
158  | 
button.peer.getRootPane.setDefaultButton(button.peer)  | 
| 
 
23601c59f347
delay to give users a chance to see what was happening, even with auto_close enabled;
 
wenzelm 
parents: 
50854 
diff
changeset
 | 
159  | 
}  | 
| 50365 | 160  | 
|
| 
50848
 
4e123d57c9b4
tuned build_dialog: auto_close checkbox avoids user sitting and waiting;
 
wenzelm 
parents: 
50846 
diff
changeset
 | 
161  | 
|
| 50369 | 162  | 
/* main build */  | 
163  | 
||
| 50374 | 164  | 
    title = "Isabelle build (" + Isabelle_System.getenv("ML_IDENTIFIER") + ")"
 | 
| 50372 | 165  | 
    progress.echo("Build started for Isabelle/" + session + " ...")
 | 
| 50369 | 166  | 
|
167  | 
    default_thread_pool.submit(() => {
 | 
|
168  | 
val (out, rc) =  | 
|
169  | 
        try {
 | 
|
170  | 
          ("",
 | 
|
| 
50405
 
366c4a602500
clarified build_dialog: regular up-to-date check (extra cost of approx. 5s startup for HOL);
 
wenzelm 
parents: 
50404 
diff
changeset
 | 
171  | 
Build.build(progress, options, build_heap = true, more_dirs = more_dirs,  | 
| 50370 | 172  | 
system_mode = system_mode, sessions = List(session)))  | 
| 50369 | 173  | 
}  | 
174  | 
        catch { case exn: Throwable => (Exn.message(exn) + "\n", 2) }
 | 
|
| 50376 | 175  | 
      Swing_Thread.now {
 | 
176  | 
progress.echo(out + (if (rc == 0) "OK\n" else "Return code: " + rc + "\n"))  | 
|
| 50740 | 177  | 
return_code = rc  | 
| 
51254
 
5bae6fc0e125
more explicit GUI components for dynamic actions;
 
wenzelm 
parents: 
51253 
diff
changeset
 | 
178  | 
delay_exit.invoke()  | 
| 50371 | 179  | 
}  | 
| 50369 | 180  | 
})  | 
| 50365 | 181  | 
}  | 
182  | 
}  | 
|
183  |