diff options
Diffstat (limited to 'src/window.inc')
-rw-r--r-- | src/window.inc | 711 |
1 files changed, 711 insertions, 0 deletions
diff --git a/src/window.inc b/src/window.inc new file mode 100644 index 0000000..a151a8d --- /dev/null +++ b/src/window.inc @@ -0,0 +1,711 @@ +% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +% +% 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 +/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 + + |