% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % % window code % % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % public words: % % window.dialog ( ) ==> ( window ) % - create a new dialog % % window.init ( window ) ==> ( ) % - initialize window % % window.show ( window ) ==> ( ) % - draw window % % window.current ( ) ==> ( window ) % - the top level window % % window.action ( ) ==> ( action ) % - recent window action % % window.input ( key_in ) ==> ( key_out ) % - handle keyboard input % % window.done ( ) ==> ( ) % - close top level window % % % constants: % - window.action % actNothing - do nothing % actExit - leave boot menu % actCloseInfo - close info window % actPassword - password entered % actStart - boot kernel % actEject - eject CD % actPowerOff - turn computer off % actReboot - reboot computer % actRedraw - redraw everything % actNoClose - don't close dialog (it's a flag) % % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % window related global variables % % all open windows are stacked here /window.list 8 array def /window.list.index 0 def % the top level window % /window.current % action selected by closing window /window.action actNothing def % window field definitions /widget.size 0 def /newfield { widget.size def /widget.size widget.size 1 add def } def /.type newfield /.x newfield /.y newfield /.width newfield /.height newfield /.width.min newfield /.position newfield /.color.fg newfield /.color.bg newfield /.font newfield /.saved newfield /.saved.areas newfield /.title newfield /.title.fg newfield /.title.bg newfield /.title.height newfield /.text newfield /.text.x newfield /.text.y newfield /.buttons newfield /.button.y newfield /.ed newfield /.ed.font newfield /.ed.list newfield /.ed.buffer.list newfield /.ed.text.list newfield /.ed.width newfield /.ed.focus newfield /.ed.pw_field newfield /.xmenu newfield /.xmenu.update newfield % window types /t_dialog 100 def /t_help 101 def /t_main 102 def /t_xmenu 103 def % actions /actNothing 0 def /actExit 1 def /actCloseInfo 2 def /actPassword 3 def /actStart 4 def /actEject 5 def /actPowerOff 6 def /actRedraw 7 def /actRedrawPanel 8 def /actInstallOK 9 def /actInstallCancel 10 def /actReboot 11 def /actRedrawBootOptionsPanel 12 def /actNoClose 0x100 def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Create new dialog window. % % ( ) ==> ( window ) % /window.dialog { widget.size array dup .type t_dialog put dup .position 8 put % centered at 8/10 of screen height dup .x 0 put dup .y 0 put dup .width.min 0 put dup .color.fg window.color.fg put dup .color.bg window.color.bg put dup .font font.normal put dup .title.fg window.title.fg put dup .title.bg window.title.bg put dup .title.height help.title.height put dup .text.x 12 put dup .text.y help.title.height 10 add put } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Handle keyboard input. % % ( key_in ) ==> ( key_out ) % /window.input { window.current .undef ne { window.current .type get dup t_dialog eq { exch dialog.input exch } if dup t_help eq { exch help.input exch } if dup t_main eq { exch main.input dialog.input exch } if dup t_xmenu eq { exch xmenu.input exch } if pop % % maybe there is an editable input field % dup 0 ne { % window.current .ed get .undef ne { % window.current .ed.font get setfont % window.current .color.fg get setcolor % window.current .ed get exch edit.input % 0 % } if % } if % only top level window gets input pop 0 } if } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Initialize window. % % ( window ) ==> ( ) % /window.init { dup .type get dup t_dialog eq { pop dialog.init return } if dup t_help eq { pop help.init return } if dup t_main eq { pop main.init return } if dup t_xmenu eq { pop xmenu.init return } if pop } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Show window. % % ( window ) ==> ( ) % /window.show { dup .type get dup t_dialog eq { pop dialog.show return } if dup t_help eq { pop help.show return } if dup t_main eq { pop main.show return } if dup t_xmenu eq { pop xmenu.show return } if pop } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Add window to list. % % ( window ) ==> ( ) % /window.push { window.list.index window.list length ge { pop return } if /window.current over def window.list window.list.index rot put /window.list.index window.list.index 1 add def } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Remove window from list. % % ( ) ==> ( window ) % /window.pop { window.list.index 0 eq { .undef return } if /window.list.index window.list.index 1 sub def window.list window.list.index get window.list window.list.index .undef put /window.current window.list.index 0 eq { .undef } { window.list window.list.index 1 sub get } ifelse def } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Close top level window. % % ( ) ==> ( ) % /window.done { window.current .undef ne { window.current dup .type get dup t_help eq { help.done } if dup t_xmenu eq { xmenu.done } if pop % restore saved background and free bg image dup .saved get .undef ne { dup .x get 1 sub over .y get 1 sub moveto dup .saved get dup restorescreen free dup .saved .undef put } if % restore & free saved background areas dup .saved.areas get .undef ne { % list of [ x y screen ] dup .saved.areas get { dup { } forall 3 1 roll moveto dup restorescreen free free } forall dup .saved.areas get free dup .saved.areas .undef put } if % free input field memory dup .ed get .undef ne { dup .ed get 2 get free % background dup .ed get free dup .ed .undef put } if dup .ed.text.list get free dup .ed.list get dup { { dup 2 get free free } forall } { pop } ifelse dup .ed.list get free pop % remove it from window list window.pop % free buttons & button list dup .buttons get dup .undef ne { dup length 0 gt { dup length 1 sub 0 1 rot { over exch get free } for } if } if free % free window free } if } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Handle keyboard input. % % ( key_in ) ==> ( key_out ) % /dialog.input { dup 0 eq { return } if /window.buttons window.current .buttons get def /has_buttons window.buttons .undef ne { window.buttons length 0 gt } { false } ifelse def dup keyEnter eq has_buttons and { window.buttons window.findselected over over get 7 get /window.action exch def get dup button.press 100000 usleep window.action actNoClose and { window.action dialog.specialaction { button.show } if } { pop window.done } ifelse pop 0 } if window.current .ed.list get { window.current .ed.list get window.current .ed.focus get get .inp_show aget false ne { dup keyDown eq over keyTab eq or { window.current .ed.focus get window.current .ed.list get over get edit.hidecursor 1 add window.current .ed.list get length mod window.current .ed.list get over get .inp_show aget false ne { } { pop 0 } ifelse window.current .ed.focus 2 index put window.current .ed.list get exch get edit.showcursor dialog.say.label pop 0 } if dup keyUp eq over keyShiftTab eq or { window.current .ed.focus get window.current .ed.list get over get edit.hidecursor 1 sub window.current .ed.list get length exch over add exch mod { dup 0 eq { exit } if window.current .ed.list get over get .inp_show aget false ne { exit } { 1 sub } ifelse } loop window.current .ed.focus 2 index put window.current .ed.list get exch get edit.showcursor dialog.say.label pop 0 } if % dup keyTab eq { % window.findselected 1 add window.buttons length mod % window.selectbutton % pop 0 % } if } if } { has_buttons { dup keyTab eq over keyRight eq or over keyDown eq or { window.findselected 1 add window.buttons length mod window.selectbutton pop 0 } if dup keyShiftTab eq over keyLeft eq or over keyUp eq or { window.findselected window.buttons length 1 sub add window.buttons length mod window.selectbutton pop 0 } if } if } ifelse has_buttons { dup window.findkey dup 0 ge { window.buttons exch over over get 7 get /window.action exch def get dup button.press 100000 usleep window.action actNoClose and { window.action dialog.specialaction { button.show } if } { pop window.done } ifelse pop 0 } { pop } ifelse } if % maybe there are input fields dup 0 ne { window.current .ed.list get dup { window.current .ed.font get window.current .ed.focus get window.current .ed.pw_field get eq { pwmode } if setfont window.current .color.fg get setcolor window.current .ed.focus get get dup .inp_show aget false ne { exch over over edit.input % only if real key 24 shr 0xff and 0xff ne config.talk and currentfont is.pwmode not and { edit.getleft dup 'A' ge over 'Z' le and { 0x20 add } if dialog.input.tmp1 0 rot put dialog.input.tmp1 speak } { pop } ifelse } { pop pop } ifelse 0 } { pop } ifelse } if } def /dialog.input.tmp1 1 string def /dialog.say.label { config.talk { window.current .ed.text.list get window.current .ed.focus get get speak } if } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Find selected button. % % ( ) ==> ( button_idx ) % /window.findselected { 0 0 1 window.buttons length 1 sub { dup window.buttons exch get 5 get { exch pop exit } { pop } ifelse } for } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Find button for key. % % ( key ) ==> ( button_idx ) % % button_idx = -1 if not found % /window.findkey { /window.key exch def -1 window.key 0 eq { return } if 0 1 window.buttons length 1 sub { dup window.buttons exch get 6 get window.key eq { exch pop exit } { pop } ifelse } for } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Select button. % % ( button_idx ) ==> ( ) % /window.selectbutton { window.findselected over over eq { pop pop } { window.buttons exch get button.notdefault button.show window.buttons exch get button.default button.show } ifelse } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Initialize dialog window. % % ( window ) ==> ( ) % /dialog.init { /dialog.tmp exch def dialog.tmp .font get setfont dialog.tmp .text get dup "" ne { strsize } { pop 0 0 } ifelse /dialog.height exch dialog.tmp .text.y get 10 add add def /dialog.width exch dialog.tmp .text.x get 1 add 2 mul add dialog.tmp .width.min get max def /dialog.width dialog.tmp .title get strsize pop dialog.tmp .text.x get 1 add 2 mul add dialog.width max def dialog.tmp .ed.text.list get dup { /dialog.width dialog.tmp .ed.width get dialog.tmp .text.x get 1 add 2 mul add 8 add dialog.width max def { strsize /dialog.height exch dialog.height add def /dialog.width exch dialog.tmp .text.x get 1 add 2 mul add dialog.width max def } forall } { pop } ifelse dialog.tmp .ed.buffer.list get dup { length lineheight 20 add mul /dialog.height exch dialog.height add def } { pop } ifelse /window.buttons dialog.tmp .buttons get def /dialog.button.y dialog.height 5 add def window.buttons .undef ne { window.buttons length { /dialog.height window.buttons 0 get 3 get dialog.button.y add 8 add def } if } if /dialog.y screen.size exch pop dialog.tmp .position get mul 10 div dialog.height sub 2 div 10 max def window.buttons .undef ne { window.buttons length { 10 0 1 window.buttons length 1 sub { window.buttons exch get dup 1 dialog.button.y dialog.y add put 2 get 10 add add } for dialog.width max /dialog.width exch def } if } if % adjust to window size dialog.tmp .ed.width get .undef ne { dialog.tmp .ed.width over over get dialog.width 30 sub max put } if /dialog.x screen.size pop dialog.width sub 2 div def window.buttons .undef ne { window.buttons length { % calculate button x positions dialog.width 0 0 1 window.buttons length 1 sub { window.buttons exch get 2 get add } for sub window.buttons length 1 add div dialog.x over add 0 1 window.buttons length 1 sub { window.buttons exch get over over 0 rot put 2 get add over add } for pop pop } if } if % store values dialog.tmp dup .x dialog.x put dup .y dialog.y put dup .width dialog.width put dup .height dialog.height put .button.y dialog.button.y put /dialog.tmp .undef def } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Draw dialog window. % % ( window ) ==> ( ) % /dialog.show { /dialog.tmp exch def % put into list early, so drawing functions can access it there dialog.tmp window.push % now start drawing dialog.tmp .x get 1 sub dialog.tmp .y get 1 sub moveto white black dialog.tmp .width get 2 add dialog.tmp .height get 2 add over over savescreen dialog.tmp .saved rot put drawborder dialog.tmp .color.bg get setcolor dialog.tmp .x get dialog.tmp .y get moveto dialog.tmp .width get dialog.tmp .height get fillrect dialog.tmp .title.bg get setcolor dialog.tmp .x get 1 add dialog.tmp .y get 1 add moveto dialog.tmp .width get 2 sub dialog.tmp .title.height get 1 sub fillrect dialog.tmp .x get 10 add dialog.tmp .y get 3 add moveto dialog.tmp .title.fg get setcolor dialog.tmp .title get config.rtl { dialog.tmp .width get 20 sub 0 rmoveto } if show.rtl dialog.tmp .color.fg get setcolor dialog.tmp .x get dialog.tmp .y get moveto dialog.tmp .text.x get dialog.tmp .text.y get rmoveto config.talk { dialog.tmp .title get speak } if /dialog.tmp.x currentpoint pop def config.rtl { dialog.tmp .text.x get -2 mul dialog.tmp .width get add 0 rmoveto } if dialog.tmp .text get config.talk { dup speak } if show.rtl currentpoint exch pop dialog.tmp.x exch moveto dialog.tmp .ed.text.list get dup { /dialog.tmp.idx 0 def { % really '2 add'? config.rtl { dialog.tmp .ed.width get 2 add 0 rmoveto } if show.rtl currentpoint exch pop dialog.tmp.x exch moveto dialog.tmp .ed.buffer.list get dialog.tmp.idx get dup { 3 7 rmoveto /dialog.tmp.buf [ currentpoint dialog.tmp .ed.width get fontheight 2 add savescreen 0 0 .undef ] def dialog.tmp.buf 3 2 index put dialog.tmp.buf 4 rot cvp length put dialog.tmp .ed.list get dialog.tmp.idx dialog.tmp.buf put currentcolor currentpoint over 1 sub over 2 sub moveto black white dialog.tmp .ed.width get 2 add fontheight 5 add drawborder moveto -3 lineheight 20 add 7 sub rmoveto setcolor currentfont % hide text in password fields dialog.tmp.idx dialog.tmp .ed.pw_field get eq { dialog.tmp .ed.font get pwmode setfont } if dialog.tmp.buf dup 3 get edit.init setfont dialog.tmp .ed.focus get dialog.tmp.idx ne { dialog.tmp.buf edit.hidecursor } { config.talk { dialog.tmp .ed.text.list get dialog.tmp.idx get speak } if } ifelse } { pop } ifelse /dialog.tmp.idx inc } forall } { pop } ifelse dialog.tmp .buttons get .undef ne { dialog.tmp .buttons get length { 0 1 dialog.tmp .buttons get length 1 sub { dialog.tmp .buttons get exch get button.show } for } if } if /dialog.tmp .undef def } def % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % Do something without closing the window. % % ( action ) ==> ( true|false ) % % Returns whether the window still exists. % /dialog.specialaction { actNoClose not and true exch dup actEject eq { bootdrive eject pop } if dup actPowerOff eq { poweroff } if dup actReboot eq { reboot } if dup actInstallOK eq { install.ok exch not exch } if % dup actInstallCancel eq { % install.cancel % exch not exch % } if pop } def