! ! Copyright (C) 2002, Simon Baldwin (simon_baldwin@yahoo.com) ! ! This program is free software; you can redistribute it and/or modify ! it under the terms of the GNU Lesser General Public License as published ! by the Free Software Foundation; either version 2.1 of the License, or ! (at your option) any later version. ! ! This program is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! GNU Lesser General Public License for more details. ! ! You should have received a copy of the GNU Lesser General Public ! License along with this program; if not, write to the Free Software ! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! System_file; #Ifndef WORDSIZE; Constant TARGET_ZCODE; Constant WORDSIZE 2; #Endif; #Ifndef TARGET_GLULX; Message "[Gtoolbar not included for non-GLULX target.]"; #Endif; #Ifdef TARGET_GLULX; #Ifndef GTOOLBAR_H; Constant GTOOLBAR_H; Message "[Including Gtoolbar.]"; ! /*----------------------------------------------------------------------+ ! | Image constants | ! +----------------------------------------------------------------------*/ ! Assign image resources numbers to pictures. This defines constants ! for icon images, but allows for the constants to be defined previously ! outside of this file by tools such as Iblorb's Bres. #Ifndef GTB_PIC1; Constant GTB_PIC1 1; #Endif; ! control #Ifndef GTB_PIC2; Constant GTB_PIC2 2; #Endif; ! collapsed #Ifndef GTB_PIC3; Constant GTB_PIC3 3; #Endif; ! spacer #Ifndef GTB_PIC4; Constant GTB_PIC4 4; #Endif; ! tier #Ifndef GTB_PIC5; Constant GTB_PIC5 5; #Endif; ! tier #Ifndef GTB_PIC6; Constant GTB_PIC6 6; #Endif; ! compass rose #Ifndef GTB_PIC7; Constant GTB_PIC7 7; #Endif; #Ifndef GTB_PIC8; Constant GTB_PIC8 8; #Endif; #Ifndef GTB_PIC9; Constant GTB_PIC9 9; #Endif; #Ifndef GTB_PIC10; Constant GTB_PIC10 10; #Endif; #Ifndef GTB_PIC11; Constant GTB_PIC11 11; #Endif; #Ifndef GTB_PIC12; Constant GTB_PIC12 12; #Endif; #Ifndef GTB_PIC13; Constant GTB_PIC13 13; #Endif; #Ifndef GTB_PIC14; Constant GTB_PIC14 14; #Endif; ! up/down #Ifndef GTB_PIC15; Constant GTB_PIC15 15; #Endif; #Ifndef GTB_PIC16; Constant GTB_PIC16 16; #Endif; ! standard #Ifndef GTB_PIC17; Constant GTB_PIC17 17; #Endif; #Ifndef GTB_PIC18; Constant GTB_PIC18 18; #Endif; #Ifndef GTB_PIC19; Constant GTB_PIC19 19; #Endif; #Ifndef GTB_PIC20; Constant GTB_PIC20 20; #Endif; #Ifndef GTB_PIC21; Constant GTB_PIC21 21; #Endif; #Ifndef GTB_PIC22; Constant GTB_PIC22 22; #Endif; #Ifndef GTB_PIC23; Constant GTB_PIC23 23; #Endif; #Ifndef GTB_PIC24; Constant GTB_PIC24 24; #Endif; #Ifndef GTB_PIC25; Constant GTB_PIC25 25; #Endif; #Ifndef GTB_PIC26; Constant GTB_PIC26 26; #Endif; #Ifndef GTB_PIC27; Constant GTB_PIC27 27; #Endif; #Ifndef GTB_PIC28; Constant GTB_PIC28 28; #Endif; #Ifndef GTB_PIC29; Constant GTB_PIC29 29; #Endif; #Ifndef GTB_PIC30; Constant GTB_PIC30 30; #Endif; #Ifndef GTB_PIC31; Constant GTB_PIC31 31; #Endif; #Ifndef GTB_PIC32; Constant GTB_PIC32 32; #Endif; ! user defined #Ifndef GTB_PIC33; Constant GTB_PIC33 33; #Endif; #Ifndef GTB_PIC34; Constant GTB_PIC34 34; #Endif; #Ifndef GTB_PIC35; Constant GTB_PIC35 35; #Endif; #Ifndef GTB_PIC36; Constant GTB_PIC36 36; #Endif; #Ifndef GTB_PIC37; Constant GTB_PIC37 37; #Endif; #Ifndef GTB_PIC38; Constant GTB_PIC38 38; #Endif; #Ifndef GTB_PIC39; Constant GTB_PIC39 39; #Endif; #Ifndef GTB_PIC40; Constant GTB_PIC40 40; #Endif; #Ifndef GTB_PIC41; Constant GTB_PIC41 41; #Endif; #Ifndef GTB_PIC42; Constant GTB_PIC42 42; #Endif; #Ifndef GTB_PIC43; Constant GTB_PIC43 43; #Endif; #Ifndef GTB_PIC44; Constant GTB_PIC44 44; #Endif; #Ifndef GTB_PIC45; Constant GTB_PIC45 45; #Endif; #Ifndef GTB_PIC46; Constant GTB_PIC46 46; #Endif; #Ifndef GTB_PIC47; Constant GTB_PIC47 47; #Endif; #Ifndef GTB_PIC48; Constant GTB_PIC48 48; #Endif; #Ifndef GTB_PIC49; Constant GTB_PIC49 49; #Endif; #Ifndef GTB_PIC50; Constant GTB_PIC50 50; #Endif; #Ifndef GTB_PIC51; Constant GTB_PIC51 51; #Endif; #Ifndef GTB_PIC52; Constant GTB_PIC52 52; #Endif; #Ifndef GTB_PIC53; Constant GTB_PIC53 53; #Endif; #Ifndef GTB_PIC54; Constant GTB_PIC54 54; #Endif; #Ifndef GTB_PIC55; Constant GTB_PIC55 55; #Endif; #Ifndef GTB_PIC56; Constant GTB_PIC56 56; #Endif; #Ifndef GTB_PIC57; Constant GTB_PIC57 57; #Endif; ! /*----------------------------------------------------------------------+ ! | Toolbar data | ! +----------------------------------------------------------------------*/ ! Toolbar release version number. Constant GTB_VERSION_NUMBER $0206; ! General toolbar colors, tuneable. #Ifndef GTB_BACKGROUND; Constant GTB_BACKGROUND $DCDCDC; #Endif; #Ifndef GTB_LIGHT_SHADE;Constant GTB_LIGHT_SHADE $FFFFFF; #Endif; #Ifndef GTB_DARK_SHADE; Constant GTB_DARK_SHADE $9A9A9A; #Endif; ! Button press time in mS, and timeout granularity, both tuneable. #Ifndef GTB_PRESS_TIMEOUT; Constant GTB_PRESS_TIMEOUT 200; #Endif; #Ifndef GTB_TIMER_GRANULARITY; Constant GTB_TIMER_GRANULARITY 50; #Endif; ! Maximum number of icons that may be displayed at a time, tuneable. #Ifndef GTB_MAXIMUM_ICONS; Constant GTB_MAXIMUM_ICONS 50; #Endif; ! Toolbar graphical window, null if none presented, and window rock, tuneable. Global gtb_toolbarwin = 0; #Ifndef GTB_TOOLBARWIN_ROCK; Constant GTB_TOOLBARWIN_ROCK 5001; #Endif; ! Toolbar visibility -- normal, or collapsed. Global gtb_visible = true; ! Note of any current pressed toolbar icon id, and timeout counter. Global gtb_pressed = 0; Global gtb_counter = 0; ! Toolbar icons descriptor list. Array gtb_default_iconlist string ">^NO|LIZG|XTRPCD|SEAQ"; Global gtb_iconlist = gtb_default_iconlist; ! Toolbar tier currently on display. Global gtb_icontier = 0; ! Toolbar icon ids and locations -- 5 entries for each icon displayed. Array gtb_coords table 5 * GTB_MAXIMUM_ICONS; ! Substituted strings -- '_' indicates overwrite, '<' prepend, '>' append. Array gtb_s_north string "_North"; Array gtb_s_south string "_South"; Array gtb_s_east string "_East"; Array gtb_s_west string "_West"; Array gtb_s_northwest string "_Northwest"; Array gtb_s_northeast string "_Northeast"; Array gtb_s_southwest string "_Southwest"; Array gtb_s_southeast string "_Southeast"; Array gtb_s_up string "_Up"; Array gtb_s_down string "_Down"; Array gtb_s_in string "_In"; Array gtb_s_out string "_Out"; Array gtb_s_look string "_Look"; Array gtb_s_inventory string "_Inventory"; Array gtb_s_wait string "_Wait"; Array gtb_s_again string "_Again"; Array gtb_s_examine string " GTB_PIC30 0 GTB_PIC26 GTB_PIC27 GTB_PIC29 0 ! A-F GTB_PIC21 0 GTB_PIC19 0 0 GTB_PIC18 0 ! G-M GTB_PIC16 GTB_PIC17 GTB_PIC25 GTB_PIC31 ! N-Q GTB_PIC24 GTB_PIC28 GTB_PIC23 0 0 0 GTB_PIC22 ! R-X 0 GTB_PIC20; ! Y-Z Array gtb_user_images --> GTB_PIC32 GTB_PIC33 GTB_PIC34 GTB_PIC35 ! a-d GTB_PIC36 GTB_PIC37 GTB_PIC38 GTB_PIC39 ! e-h GTB_PIC40 GTB_PIC41 GTB_PIC42 GTB_PIC43 ! i-l GTB_PIC44 GTB_PIC45 GTB_PIC46 GTB_PIC47 ! m-p GTB_PIC48 GTB_PIC49 GTB_PIC50 GTB_PIC51 ! q-t GTB_PIC52 GTB_PIC53 GTB_PIC54 GTB_PIC55 ! u-x GTB_PIC56 GTB_PIC57; ! y-z ! General purpose Glk arguments. Array gtb_glkargs --> 8; ! /*----------------------------------------------------------------------+ ! | General toolbar functions | ! +----------------------------------------------------------------------*/ ! Display a modest 3-d effect around a region. [ gtb_outline3d lowered x y w h tls brs; ! Decide shading based on whether the region is lowered or raised. if (lowered) { tls = GTB_DARK_SHADE; brs = GTB_LIGHT_SHADE; } else { tls = GTB_LIGHT_SHADE; brs = GTB_DARK_SHADE; } ! Fill areas above, left, below, and right with shading. glk ($EA, gtb_toolbarwin, tls, x, y, w, 1); glk ($EA, gtb_toolbarwin, tls, x, y, 1, h); glk ($EA, gtb_toolbarwin, brs, x + 2, y + h - 1, w - 2, 1); glk ($EA, gtb_toolbarwin, brs, x + w - 1, y + 2, 1, w - 2); ]; ! Display an icon, and note its coordinates for mouse press checks. [ gtb_icon pic x y w h index i; ! Refuse, silently, if not enough coordinate array entries. if (index + 4 > gtb_coords-->0) return index; ! Render, with a cheap button press effect if pressed. if (pic == gtb_pressed) { glk ($E1, gtb_toolbarwin, pic, x + 1, y + 1); ! draw image gtb_outline3d (true, x, y, w, h); } else glk ($E1, gtb_toolbarwin, pic, x, y); ! draw image ! Note button image and coordinates. i = index; ! coords index gtb_coords-->i++ = pic; gtb_coords-->i++ = x; gtb_coords-->i++ = y; gtb_coords-->i++ = x + w; gtb_coords-->i++ = y + h; ! Return next index to use. return i; ]; ! Paint in the toolbar. [ gtb_paint x y w h ww wh i tier c id pic; glk ($EB, gtb_toolbarwin, GTB_BACKGROUND); ! set background color glk ($2A, gtb_toolbarwin); ! clear ! Clear all current icon images and coordinates. for (i = 1: i <= gtb_coords-->0: i++) gtb_coords-->i = 0; ! Start icon image and coordinate entries at 1. i = 1; ! If collapsed, paint only the horizontal control separator. if (~~gtb_visible) { glk ($E0, GTB_PIC2, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1;! get width and height x = 2; y = 0; i = gtb_icon (GTB_PIC2, x, y, w, h, i); return; } ! Paint a small 3-d effect. glk ($25, gtb_toolbarwin, gtb_glkargs, gtb_glkargs + WORDSIZE); ww = gtb_glkargs-->0; wh = gtb_glkargs-->1; ! get window size gtb_outline3d (false, 0, 0, ww, wh); ! Start with control separator. glk ($E0, GTB_PIC1, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; ! get width and height x = 2; y = 2; i = gtb_icon (GTB_PIC1, x, y, w, h, i); x = x + w + 2; ! Paint icons according to the descriptor list. tier = 0; for (c = 1: c <= gtb_iconlist->0: c++) { ! Tier switching controls. switch (gtb_iconlist->c) { ':': ! Tier separator if (tier == gtb_icontier) { x = x + 2; glk ($E0, GTB_PIC4, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC4, x, y, w, h, i); x = x + w + 2; } tier++; if (tier == gtb_icontier) { x = x + 2; glk ($E0, GTB_PIC5, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC5, x, y, w, h, i); x = x + w + 2; } continue; } ! Skip icons if not this tier if (tier ~= gtb_icontier) continue; ! Toolbar paint. switch (gtb_iconlist->c) { '>': ! Compass rose x = x + 2; glk ($E0, GTB_PIC6, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC6, x, y, w, h, i); y = y + h; glk ($E0, GTB_PIC9, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC9, x, y, w, h, i); y = y + h; glk ($E0, GTB_PIC11, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC11, x, y, w, h, i); x = x + w; glk ($E0, GTB_PIC7, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; y = 2; i = gtb_icon (GTB_PIC7, x, y, w, h, i); y = y + h; glk ($E0, GTB_PIC12, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC12, x, y, w, h, i); x = x + w; glk ($E0, GTB_PIC8, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; y = 2; i = gtb_icon (GTB_PIC8, x, y, w, h, i); y = y + h; glk ($E0, GTB_PIC10, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC10, x, y, w, h, i); y = y + h; glk ($E0, GTB_PIC13, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC13, x, y, w, h, i); x = x + w + 2; y = 2; continue; '^': ! Up/down x = x + 2; glk ($E0, GTB_PIC14, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC14, x, y, w, h, i); y = y + h; glk ($E0, GTB_PIC15, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC15, x, y, w, h, i); x = x + w + 2; y = 2; continue; '|','!': ! Separator. x = x + 2; glk ($E0, GTB_PIC3, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (GTB_PIC3, x, y, w, h, i); x = x + w + 2; continue; 'A','C','D','E','G','I','L','N', ! standard 'O','P','Q','R','S','T','X','Z': id = gtb_iconlist->c; pic = gtb_images-->(id - 'A'); 'a' to 'z': ! user defined id = gtb_iconlist->c; pic = gtb_user_images-->(id - 'a'); default: ! unknown list entry continue; } ! Paint the icon identified above. glk ($E0, pic, gtb_glkargs, gtb_glkargs + WORDSIZE); w = gtb_glkargs-->0; h = gtb_glkargs-->1; i = gtb_icon (pic, x, y, w, h, i); x = x + w; } ]; ! Set toolbar visibility, and resize the window if necessary. [ gtb_visibility v h p; ! Find required height from the separator. gtb_visible = v; if (gtb_visible) { glk ($E0, GTB_PIC1, 0, gtb_glkargs); h = gtb_glkargs-->0 + 4; ! get height, add 4 } else { glk ($E0, GTB_PIC2, 0, gtb_glkargs); h = gtb_glkargs-->0; ! get height } ! Resize to this height. p = glk ($29, gtb_toolbarwin); ! get parent glk ($26, p, $12, h, 0); ! resize ! Paint the new appearance. gtb_paint (); ]; ! Synchronize toolbar visibility with window height, following restart. [ gtb_synchronize_visibility h wh; ! Get current toolbar window height. glk ($25, gtb_toolbarwin, 0, gtb_glkargs); wh = gtb_glkargs-->0; ! get window height ! Get expected window height when collapsed. glk ($E0, GTB_PIC2, 0, gtb_glkargs); h = gtb_glkargs-->0; ! get height ! Set visibility flag depending on current window height, repaint. gtb_visible = (wh > h); gtb_paint (); ]; ! Look for mouse event in a toolbar icon, return icon id. [ gtb_icon_click event i x y; ! Get mouse coordinates. x = event-->2; y = event-->3; ! Check coordinates table for a match, stopping either at the table ! end, or on the first empty entry. for (i = 1: i <= gtb_coords-->0 && gtb_coords-->i ~= 0: i = i + 5) { ! Check if this event is inside the saved coordinates. if (x >= gtb_coords-->(i + 1) && y >= gtb_coords-->(i + 2) && x <= gtb_coords-->(i + 3) && y <= gtb_coords-->(i + 4)) { return gtb_coords-->i; } } ! No match. return 0; ]; ! Create the toolbar if doable and not yet done. [ gtb_initialize h; ! Check Glk library capabilities. if (gtb_toolbarwin == 0 && glk ($04, 6, 0) ! graphics && glk ($04, 4, 5) ! mouse graphics events && glk ($04, 5, 0)) { ! timer events ! Discern initial toolbar height from the vertical separator. glk ($E0, GTB_PIC1, 0, gtb_glkargs); h = gtb_glkargs-->0; ! get height ! Split main window to create toolbar at the top. gtb_toolbarwin = glk ($23, gg_mainwin, $12, h + 4, 5, GTB_TOOLBARWIN_ROCK); if (gtb_toolbarwin == 0) return; ! Paint according to the current visibility flag. gtb_visibility (gtb_visible); ! Request mouse events for the toolbar window. glk ($D4, gtb_toolbarwin); ! request mouse event } ]; ! Echo a buffer as if new input. [ gtb_echo a_buffer i; print ">"; glk ($86, 8); ! set input style ! Echo the overwritten buffer as if new input. for (i = WORDSIZE: i < a_buffer-->0 + WORDSIZE: i++) { print (char) a_buffer->i; } glk ($86, 0); ! set normal style print "^"; ]; ! Substitute an icon string into an input buffer. [ gtb_overwrite subst a_buffer i; ! Cancel any partial line event and simply ditch it. glk ($D1, gg_mainwin, 0); ! cancel line event ! Place the substitution string into the buffer. for (i = 2: i <= subst->0: i++) { a_buffer->(WORDSIZE + i - 2) = subst->i; } a_buffer-->0 = subst->0 - 1; ! Echo the buffer. gtb_echo (a_buffer); ! Always return true. return true; ]; ! Limited string compare, checks start of string. [ gtb_startswith subst a_buffer len s i; ! Skip leading spaces in buffer; false if nothing left. s = 0; while (s < len && a_buffer->(WORDSIZE + s) == ' ') s++; if (s == len) return false; ! Compare characters up the end of substitute string, ignore case. for (i = 2: i <= subst->0: i++) { if (s + i - 2 >= len || glk ($A1, a_buffer->(WORDSIZE + s + i - 2)) ~= glk ($A1, subst->i)) return false; } if (s + i - 2 < len && a_buffer->(WORDSIZE + s + i - 2) ~= ' ') return false; ! Return matched. return true; ]; ! Only slightly smart prepend of an icon string to an input buffer. [ gtb_prepend subst a_buffer len slen found i str; ! Cancel any partial line event but retain data. glk ($D1, gg_mainwin, gtb_glkargs); ! cancel line event if (gtb_glkargs-->0 ~= 3) return false; ! no line request(?) len = gtb_glkargs-->2; ! buffered data len a_buffer-->0 = len; ! Separate cases of data entered so far, and nothing so far. if (len > 0) { ! See if buffer seems to contain a prependable toolbar string. found = false; for (i = 1: i <= gtb_iconstrings-->0: i = i + 2) { str = gtb_iconstrings-->(i + 1); if (str ~= 0 && str->1 == '<' && gtb_startswith (str, a_buffer, len)) { found = true; break; } } ! If it looks like it does, reissue the line request. if (found) { print ">"; glk ($D0, gg_mainwin, ! request line event a_buffer + WORDSIZE, INPUT_BUFFER_LEN - WORDSIZE, len); return false; } ! Prepend line so far with the substitute string, if it fits. slen = subst->0 - 1; if (len + slen + 1 < INPUT_BUFFER_LEN - WORDSIZE) { for (i = len - 1: i >= 0: i--) { a_buffer->(WORDSIZE + i + slen + 1) = a_buffer->(WORDSIZE + i); } for (i = 2: i <= subst->0: i++) { a_buffer->(WORDSIZE + i - 2) = subst->i; } a_buffer->(WORDSIZE + i - 2) = ' '; a_buffer-->0 = a_buffer-->0 + slen + 1; } ! Echo the buffer. gtb_echo (a_buffer); ! Input considered done -- return true. return true; } else { ! Start buffer with substitute string, and invite more input. slen = subst->0 - 1; for (i = 2: i <= subst->0: i++) { a_buffer->(WORDSIZE + i - 2) = subst->i; } a_buffer->(WORDSIZE + i - 2) = ' '; print ">"; glk ($D0, gg_mainwin, ! request line event a_buffer + WORDSIZE, INPUT_BUFFER_LEN - WORDSIZE, slen + 1); ! Input not considered done -- return false. return false; } ]; ! Even less smart append of an icon string to an input buffer. [ gtb_append subst a_buffer len slen i; ! Cancel any partial line event but retain data. glk ($D1, gg_mainwin, gtb_glkargs); ! cancel line event if (gtb_glkargs-->0 ~= 3) return false; ! no line request(?) len = gtb_glkargs-->2; ! buffered data len a_buffer-->0 = len; ! Only append if there is something to append to. if (len > 0) { ! Append the string, with a space, if it fits. slen = subst->0 - 1; if (len + slen + 1 < INPUT_BUFFER_LEN - WORDSIZE) { a_buffer->(WORDSIZE + len) = ' '; for (i = 2: i <= subst->0: i++) { a_buffer->(WORDSIZE + len + i - 1) = subst->i; } a_buffer-->0 = a_buffer-->0 + slen + 1; } ! Echo the buffer. gtb_echo (a_buffer); ! Input considered done -- return true. return true; } else { ! Nothing to append to, so simply reissue line request. print ">"; glk ($D0, gg_mainwin, ! request line event a_buffer + WORDSIZE, INPUT_BUFFER_LEN - WORDSIZE, 0); ! Input not considered done -- return false. return false; } ]; ! Event handler for toolbar mouse events. [ gtb_mouse_event event context res pic i str; ! Keep rolling request for mouse events. glk ($D4, gtb_toolbarwin); ! request mouse event ! Test for a click on a toolbar icon. pic = gtb_icon_click (event); ! Offer the game a chance to handle the toolbar event. res = GtbToolbarEvent (pic, 0, context); switch (res) { -1: ! game handled totally return; 2: ! game handled switch (pic) { 0, GTB_PIC1, GTB_PIC2, GTB_PIC3, GTB_PIC4, GTB_PIC5: return; default: gtb_pressed = pic; gtb_paint (); gtb_counter = GTB_PRESS_TIMEOUT;! short delay callback glk ($D6, GTB_TIMER_GRANULARITY); return; } } ! Handle special icon ids: none, collapse/reinstate, spacer, and tier. switch (pic) { 0: return; ! no icon GTB_PIC1: gtb_visibility (false); ! collapse toolbar return; GTB_PIC2: gtb_visibility (true); ! reinstate toolbar return; GTB_PIC3: return; ! null separator GTB_PIC4: gtb_icontier++; gtb_paint (); ! next tier return; GTB_PIC5: gtb_icontier--; gtb_paint (); ! prior tier return; } ! Was the event from the KeyboardPrimitive? switch (context) { 0: ! KeyboardPrimitive ! Find the string, if any, associated with the icon. str = 0; for (i = 1: i <= gtb_iconstrings-->0: i = i + 2) { if (gtb_iconstrings-->i == pic) { str = gtb_iconstrings-->(i + 1); break; } } ! If there is an icon string, note id and request callback. if (str ~= 0) { gtb_pressed = pic; gtb_paint (); gtb_counter = GTB_PRESS_TIMEOUT;! short delay callback glk ($D6, GTB_TIMER_GRANULARITY); } } ]; ! Event handler for timer events. [ gtb_timer_event arg pic i str res; ! Do nothing if no timer event is expected. if (gtb_pressed == 0) return false; ! Reduce timeouts counter, and do nothing if still above zero. gtb_counter = gtb_counter - GTB_TIMER_GRANULARITY; if (gtb_counter > 0) return false; ! Note the pressed icon, and cancel press display. pic = gtb_pressed; gtb_pressed = 0; gtb_paint (); gtb_counter = 0; ! cancel timer glk ($D6, 0); ! Offer the game a chance to handle the toolbar timeout. res = GtbToolbarEvent (pic, 1, arg); switch (res) { -1, 2: ! game handled totally return false; } ! Obtain the substitution string for the pressed icon, and do no ! more if it indicates a null string or there isn't a matching entry. str = 0; for (i = 1: i <= gtb_iconstrings-->0: i = i + 2) { if (gtb_iconstrings-->i == pic) { str = gtb_iconstrings-->(i + 1); break; } } ! If there is an icon string, alter the input buffer. if (str ~= 0) { ! Substitute the string into the buffer. switch (str->1) { '<': res = gtb_prepend (str, arg); ! buffer prepend '_': res = gtb_overwrite (str, arg); ! buffer overwrite '>': res = gtb_append (str, arg); ! buffer append default: ! strings table error return false; } ! Pass on a final entry point, and return. GtbToolbarEvent (pic, 2, arg); return res; } ! No icon string for this icon. return false; ]; ! /*----------------------------------------------------------------------+ ! | Entry point functions | ! +----------------------------------------------------------------------*/ ! Glk event handler entry point. [ HandleGlkEvent event context abortres done res; ! If no toolbar window is available, ignore the event. done = false; if (gtb_toolbarwin ~= 0) { ! Note events only from either the KeyboardPrimitive[0] or ! KeyCharPrimitive[1] functions. switch (context) { 0, 1: ! primitive switch (event-->0) { 4: ! mouse if (event-->1 == gtb_toolbarwin) gtb_mouse_event (event, context); 1: ! timer done = gtb_timer_event (abortres); 5, 6: ! arrange/redraw gtb_paint (); } } } ! Chain entry point, and allow it some override of return value. res = GtbHandleGlkEvent (event, context, abortres); switch (res) { -1, 2: return res; } ! Return 2, special code to exit KeyboardPrimitive, if we expect line ! input to terminate, otherwise return chained entry result. if (done) return 2; return res; ]; ! Glk window initialization entry point. [ InitGlkWindow winrock res; ! Intercept status window creation. Ideally, we'd create the toolbar ! on main window creation, but in practice since the status window is ! always created after the main window, and that's the one we want to ! split, it's a little easier to leave it until here. switch (winrock) { GG_STATUSWIN_ROCK: ! Create a toolbar at mainwin top, allowing game first dibs. res = GtbInitGlkWindow (GTB_TOOLBARWIN_ROCK); if (res == 0) gtb_initialize (); } ! Chain entry point. return GtbInitGlkWindow (winrock); ]; ! Glk object identification entry point. [ IdentifyGlkObject phase type ref rock; ! Reassert control over the toolbar following restart. switch (phase) { 0: ! start gtb_toolbarwin = 0; 1: ! pass ref switch (type) { 0: ! window ref if (rock == GTB_TOOLBARWIN_ROCK) { gtb_toolbarwin = ref; return; } } 2: ! tidy up if (gtb_toolbarwin ~= 0) { gtb_synchronize_visibility (); } } ! Chain entry point. return GtbIdentifyGlkObject (phase, type, ref, rock); ]; ! Inform after-prompt entry point. [ AfterPrompt; ! The Xglk library loses mouse events inside its save/restore ! file dialogs. This means that we can find ourselves without ! an outstanding mouse request on the toolbar, which makes it ! stop working. To get around this, here we'll request mouse ! events on each game prompt issued, relying on the fact that, ! unlike char and line events, the Glk library doesn't complain ! if a mouse event is already requested. And, unfortunately, ! this means that we have to take control of this entry point... if (gtb_toolbarwin ~= 0) glk ($D4, gtb_toolbarwin); ! request mouse event ! Chain entry point. return GtbAfterPrompt (); ]; ! /*----------------------------------------------------------------------+ ! | Entry point stub functions | ! +----------------------------------------------------------------------*/ ! Chaining entry point stubs. #Ifndef Replace_GtbIdentifyGlkObject; #Stub GtbIdentifyGlkObject 4; #Endif; #Ifndef Replace_GtbHandleGlkEvent; #Stub GtbHandleGlkEvent 2; #Endif; #Ifndef Replace_GtbInitGlkWindow; #Stub GtbInitGlkWindow 1; #Endif; #Ifndef Replace_GtbAfterPrompt; #Stub GtbAfterPrompt 0; #Endif; ! Private entry point stub. #Ifndef Replace_GtbToolbarEvent; #Stub GtbToolbarEvent 3; #Endif; ! /*----------------------------------------------------------------------+ ! | Programming interface functions | ! +----------------------------------------------------------------------*/ ! Return toolbar code version. [ gtb_version; return GTB_VERSION_NUMBER; ]; ! Print Gtoolbar identification string. [ gtb_print_ident maj min; ! Get major/minor version components. maj = GTB_VERSION_NUMBER / 256; min = GTB_VERSION_NUMBER % 256; ! Print out a minimally formatted ident. print "Gtoolbar v", maj, "."; if (min < 10) print "0", min; else print min; ]; ! Query if a toolbar is available. [ gtb_is_available; return (gtb_toolbarwin ~= 0); ]; ! Query and set toolbar visibility. [ gtb_get_visible; return (gtb_toolbarwin ~= 0 && gtb_visible); ]; [ gtb_set_visible flag; ! If displayed, update, otherwise just save flag. if (gtb_toolbarwin ~= 0) gtb_visibility (flag); else gtb_visible = flag; ]; ! Query and set icon display list and tier. [ gtb_get_icon_list; return gtb_iconlist; ]; [ gtb_get_icon_tier; return gtb_icontier; ]; [ gtb_set_icon_list list tier; ! varargs ! If null list passed in, set default, otherwise set list. if (list == 0) gtb_iconlist = gtb_default_iconlist; else gtb_iconlist = list; gtb_icontier = tier; if (gtb_toolbarwin ~= 0 && gtb_visible) gtb_paint (); ]; [ gtb_set_icon_tier tier; gtb_icontier = tier; if (gtb_toolbarwin ~= 0 && gtb_visible) gtb_paint (); ]; ! Query and set icon strings. [ gtb_get_icon_string id index ! varargs pic i; ! Convert character id/index into an image number. switch (id) { '>': ! Compass rose switch (index) { 1: pic = GTB_PIC6; 2: pic = GTB_PIC7; 3: pic = GTB_PIC8; 4: pic = GTB_PIC9; 5: pic = GTB_PIC10; 6: pic = GTB_PIC11; 7: pic = GTB_PIC12; 8: pic = GTB_PIC13; default: return -1; } '^': ! Up/down switch (index) { 1: pic = GTB_PIC14; 2: pic = GTB_PIC15; default: return -1; } 'A','C','D','E','G','I','L','N', ! standard 'O','P','Q','R','S','T','X','Z': pic = gtb_images-->(id - 'A'); 'a' to 'z': ! user defined pic = gtb_user_images-->(id - 'a'); default: return -1; } ! Find and return the string associated with the icon. for (i = 1: i <= gtb_iconstrings-->0: i = i + 2) { if (gtb_iconstrings-->i == pic) return gtb_iconstrings-->(i + 1); } return -1; ! strings table error ]; [ gtb_set_icon_string id str index ! varargs pic i; ! Verify that the icon string, if present, has valid format. if (str ~= 0) { if (str->0 < 1 || str->1 ~= '_' or '<' or '>') return false; } ! Convert character id/index into an image number. switch (id) { '>': ! Compass rose switch (index) { 1: pic = GTB_PIC6; 2: pic = GTB_PIC7; 3: pic = GTB_PIC8; 4: pic = GTB_PIC9; 5: pic = GTB_PIC10; 6: pic = GTB_PIC11; 7: pic = GTB_PIC12; 8: pic = GTB_PIC13; default: return false; } '^': ! Up/down switch (index) { 1: pic = GTB_PIC14; 2: pic = GTB_PIC15; default: return false; } 'A','C','D','E','G','I','L','N', ! standard 'O','P','Q','R','S','T','X','Z': pic = gtb_images-->(id - 'A'); 'a' to 'z': ! user defined pic = gtb_user_images-->(id - 'a'); default: return false; } ! Find and set the string associated with the icon. for (i = 1: i <= gtb_iconstrings-->0: i = i + 2) { if (gtb_iconstrings-->i == pic) { gtb_iconstrings-->(i + 1) = str; return true; } } return false; ! strings table error ]; ! Create a new toolbar if none yet done. [ gtb_create sr sh; ! If there is currently no toolbar create one. if (gtb_toolbarwin == 0) { ! In order to get the toolbar to the top of the display, ! here we'll have to close, then recreate the status window. if (gg_statuswin ~= 0) { ! Save current status window attributes, then close. sr = glk ($21, gg_statuswin); ! get rock glk ($25, gg_statuswin, 0, gtb_glkargs); sh = gtb_glkargs-->0; ! get height glk ($24, gg_statuswin, 0); ! close window ! Create the toolbar window. gtb_initialize (); ! Resplit main to reinstate the status window gg_statuswin = glk ($23, gg_mainwin, $12, sh, 4, sr); DrawStatusLine (); } else { ! Unlikely, but if no status window just do toolbar. gtb_initialize (); } } return (gtb_toolbarwin ~= 0); ]; ! Remove the toolbar from the display. [ gtb_destroy; ! Close any open toolbar window. if (gtb_toolbarwin ~= 0) { glk ($24, gtb_toolbarwin, 0); ! close window gtb_toolbarwin = 0; } ]; #Endif; #Endif;