% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % % 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 /.xmenu.change newfield % like update but the window remains shown /.xmenu.select newfield /.xmenu.input newfield /.xmenu.cleanup newfield % window types /t_dialog 100 def /t_help 101 def /t_splash 102 def /t_main 103 def /t_xmenu 104 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 /actReboot 9 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 black put dup .color.bg lightgray put dup .font font.normal put dup .title.fg white put dup .title.bg 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_splash eq { exch splash.input exch } if dup t_main eq { exch main.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 ed.color 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_splash eq { pop splash.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_splash eq { pop splash.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 dec 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 % specific cleanup actions window.current .type get dup t_xmenu eq { xmenu.cleanup } if pop % 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 window.buttons .undef ne { window.buttons length { dup keyEnter eq { 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 { 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.focus 2 index put window.current .ed.list get exch get edit.showcursor 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 window.current .ed.focus 2 index put window.current .ed.list get exch get edit.showcursor pop 0 } if % dup keyTab eq { % window.findselected 1 add window.buttons length mod % window.selectbutton % pop 0 % } if } { 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 keyLeft eq over keyUp eq or { window.findselected window.buttons length 1 sub add window.buttons length mod window.selectbutton pop 0 } if } ifelse 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 } 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 ed.color setcolor window.current .ed.focus get get exch edit.input 0 } { pop } ifelse } 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 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 show 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 dialog.tmp .text get show dialog.tmp .ed.text.list get dup { /dialog.tmp.idx 0 def { show 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 0 0 0 ] 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 } if } { 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 pop } def