diff --git a/.editorconfig b/.editorconfig index 3b02053a52..f246a51a4b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,6 +12,9 @@ insert_final_newline = false [*.{i6t,i7,i7x,neptune,ni,txt,w}] indent_style = tab +[*.{i6t,w}] +insert_final_newline = true + [*.json] indent_style = space indent_size = 4 @@ -20,4 +23,4 @@ indent_size = 4 indent_style = tab [resources/Documentation/**.txt] -indent_style = tab +indent_style = tab \ No newline at end of file diff --git a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/Glk.i6t b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/Glk.i6t index f846e7f3b5..08f077bf9c 100644 --- a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/Glk.i6t +++ b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/Glk.i6t @@ -479,7 +479,7 @@ be used by |glk_select|. It also handles a few event maintenance tasks. evtype_MouseInput: win_obj.requesting_mouse = false; evtype_Hyperlink: - win_obj.requesting_hyperlink = false; + glk_request_hyperlink_event(win_obj.glk_ref); } return ev; ]; @@ -500,7 +500,7 @@ the event struct. event_struct-->3 = ev-->GLK_EVENT_VALUE2_SF; ]; -@ |GLK_EVENT_TY_Handle_Instead| applies a glk event onto the current glk event, and +@ |GLK_EVENT_TY_Replace_Current| applies a glk event onto the current glk event, and tells glk_select to re-run the glk event handling rules. It also ensures that if there are any pending keyboard input requests they will be cancelled if the new event is a keyboard event. @@ -508,12 +508,12 @@ new event is a keyboard event. = Array current_glk_event --> [ BLK_BVBITMAP_SBONLY; GLK_EVENT_TY; 0; 0; 0; 0; 0; 0; 0; ]; -Constant GLK_EVENT_HANDLING_INACTIVE 0; -Constant GLK_EVENT_HANDLING_ACTIVE 1; -Constant GLK_EVENT_HANDLING_REHANDLING 2; +Constant GLK_EVENT_HANDLING_INACTIVE 0; +Constant GLK_EVENT_HANDLING_ACTIVE 1; +Constant GLK_EVENT_HANDLING_REPLACED 2; Global glk_event_handling_status = GLK_EVENT_HANDLING_INACTIVE; -[ GLK_EVENT_TY_Handle_Instead ev evtype win_obj; +[ GLK_EVENT_TY_Replace_Current ev evtype win_obj; if (glk_event_handling_status == GLK_EVENT_HANDLING_INACTIVE) { IssueRTP("EventHandledWhileInactive", "Cannot handle new event while not handling events.", Architecture32KitRTPs); RulebookSucceeds(); @@ -550,7 +550,7 @@ Global glk_event_handling_status = GLK_EVENT_HANDLING_INACTIVE; current_glk_event-->GLK_EVENT_VALUE2_SF = ev-->GLK_EVENT_VALUE2_SF; RulebookSucceeds(); - glk_event_handling_status = GLK_EVENT_HANDLING_REHANDLING; + glk_event_handling_status = GLK_EVENT_HANDLING_REPLACED; ]; @ To handle events we intercept the |glk_select| function. This allows us to handle @@ -633,16 +633,6 @@ requested. return 0; ]; -[ glk_cancel_hyperlink_event win win_obj; - @push win; - @glk 259 1 0; - win_obj = FindGlkWindowFromRefNum(win); - if (win_obj) { - win_obj.requesting_hyperlink = false; - } - return 0; -]; - [ glk_cancel_line_event win event_struct win_obj; if (event_struct == 0) { event_struct = gg_arguments; @@ -688,16 +678,6 @@ requested. return 0; ]; -[ glk_request_hyperlink_event win win_obj; - @push win; - @glk 258 1 0; - win_obj = FindGlkWindowFromRefNum(win); - if (win_obj) { - win_obj.requesting_hyperlink = true; - } - return 0; -]; - [ glk_request_line_event win buf maxlen initlen win_obj; @push initlen; @push maxlen; @@ -740,6 +720,88 @@ requested. return 0; ]; +@h Hyperlinks. +A simple framework for handling hyperlinks in an interoperable manner. +We combine a hyperlink tag with a payload in one 32-bit value. The tag is stored +in the lowest bits, and the payload above it. + +|CALCULATE_HYPERLINK_TAG_WIDTH_R| is a |before starting the virtual machine| rule, +which gets the number of options in the hyperlink tag enum and sets the tag/payload +masks and widths accordingly. + += +Global hyperlink_payload_mask; +Global hyperlink_tag_mask; +Global hyperlink_tag_width; +Global hyperlink_value; + +[ CALCULATE_HYPERLINK_TAG_WIDTH_R; + if (ICOUNT_HYPERLINK_TAG < 8) { + hyperlink_tag_mask = $07; + hyperlink_tag_width = 3; + } + else if (ICOUNT_HYPERLINK_TAG < 16) { + hyperlink_tag_mask = $0F; + hyperlink_tag_width = 4; + } + else { + ! Enough for 31 tags, which better be enough! + hyperlink_tag_mask = $1F; + hyperlink_tag_width = 5; + } + hyperlink_payload_mask = ~hyperlink_tag_mask; + rfalse; +]; + +@ |MakeTaggedHyperlink| combines the tag and value into one 32 bit hyperlink ID, +checking that the value is not a pointer to ephemeral data (on the stack). + +|HANDLE_HYPERLINK_R| then extracts tag and value from an ID, expanding the value +back to 32 bits. + += + +[ MakeTaggedHyperlink tag val kind; + if (Cached_Glk_Gestalts-->gestalt_Hyperlinks) { + #Ifdef DEBUG; + if (val >= blockv_stack && val < (blockv_stack + BLOCKV_STACK_SIZE * WORDSIZE)) { + if (kind) { + if (KindConformsTo_POINTER_VALUE_TY(kind)) { + ! Break up the message so that Inform doesn't think it's an Inter invocation + print "Error: cannot make hyperlink from ephemeral value; try creating with {", "-by-reference:V}^"; + return; + } + } + else { + print "Warning: hyperlink value might be ephemeral; try creating with explicit kind^"; + } + } + #Endif; ! DEBUG + if (val > 0) { + @shiftl val hyperlink_tag_width val; + } + else { + val = val & hyperlink_payload_mask; + } + glk_set_hyperlink(tag | val); + } +]; + +[ HANDLE_HYPERLINK_R val; + if (current_glk_event-->GLK_EVENT_TYPE_SF == evtype_Hyperlink) { + val = current_glk_event-->GLK_EVENT_VALUE1_SF; + hyperlink_value = val & hyperlink_payload_mask; + if (hyperlink_value < 0) { + hyperlink_value = hyperlink_value | hyperlink_tag_mask; + } + else { + @ushiftr hyperlink_value hyperlink_tag_width hyperlink_value; + } + FollowRulebook(HYPERLINK_HANDLING_RB, val & hyperlink_tag_mask, true); + } + rfalse; +]; + @h Suspending and resuming text input. These functions allow the author to suspend and then resume a window's text input requests. diff --git a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/InfGlk.i6t b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/InfGlk.i6t index 011d5af3be..5bb7d391a7 100644 --- a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/InfGlk.i6t +++ b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/InfGlk.i6t @@ -690,17 +690,17 @@ Constant wintype_TextGrid = 4; return 0; ]; -![ glk_request_hyperlink_event _vararg_count; -! ! glk_request_hyperlink_event(window) -! @glk 258 _vararg_count 0; -! return 0; -!]; +[ glk_request_hyperlink_event _vararg_count; + ! glk_request_hyperlink_event(window) + @glk 258 _vararg_count 0; + return 0; +]; -![ glk_cancel_hyperlink_event _vararg_count; -! ! glk_cancel_hyperlink_event(window) -! @glk 259 _vararg_count 0; -! return 0; -!]; +[ glk_cancel_hyperlink_event _vararg_count; + ! glk_cancel_hyperlink_event(window) + @glk 259 _vararg_count 0; + return 0; +]; [ glk_buffer_to_lower_case_uni _vararg_count ret; ! glk_buffer_to_lower_case_uni(uintarray, arraylen, uint) => uint @@ -921,4 +921,4 @@ Constant zcolor_Current = -2; ! garglk_set_reversevideo_stream(str, reverse) @glk $1103 _vararg_count 0; return 0; -]; \ No newline at end of file +]; diff --git a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/Startup.i6t b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/Startup.i6t index 902b76b0ea..3cecc6360b 100644 --- a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/Startup.i6t +++ b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Materials/Inter/Architecture32Kit/Sections/Startup.i6t @@ -113,6 +113,9 @@ Global Pre_Startup_Text_Capture_Stream; if (BasicInformKit`MANUAL_INPUT_ECHOING_CFGF && Cached_Glk_Gestalts-->gestalt_LineInputEcho) { glk_set_echo_line_event(gg_mainwin, 0); } + if (Cached_Glk_Gestalts-->gestalt_Hyperlinks) { + glk_request_hyperlink_event(gg_mainwin); + } } else { ! There was already a story window. We should erase it. glk_window_clear(gg_mainwin); @@ -124,6 +127,9 @@ Global Pre_Startup_Text_Capture_Stream; gg_statuswin = glk_window_open(gg_mainwin, winmethod_Fixed + winmethod_Above, statuswin_cursize, wintype_TextGrid, GG_STATUSWIN_ROCK); + if (Cached_Glk_Gestalts-->gestalt_Hyperlinks) { + glk_request_hyperlink_event(gg_statuswin); + } } } else if (gg_statuswin) { diff --git a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Glulx and Glk.w b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Glulx and Glk.w index c93638e02e..d173486325 100644 --- a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Glulx and Glk.w +++ b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Glulx and Glk.w @@ -189,12 +189,61 @@ Very first glk event handling rule for a glk event type (this is the set glk event processing variables rule): now the event is the current glk event initialiser. -To handle (ev - glk event): - (- GLK_EVENT_TY_Handle_Instead({ev}); rtrue; -). +To replace current event with (ev - glk event): + (- GLK_EVENT_TY_Replace_Current({ev}); rtrue; -). Glk event handling rule for a screen resize event (this is the redraw the status line rule): redraw the status window; +@h Hyperlinks. +A simple framework for handling hyperlinks in an interoperable manner. + += +Chapter - Hyperlinks + +A hyperlink tag is a kind of value. + +The hyperlink handling rules is a hyperlink tag based rulebook. +The hyperlink handling rules is accessible to Inter as "HYPERLINK_HANDLING_RB". + +The handle hyperlinks rule is listed in the glk event handling rules. +The handle hyperlinks rule is defined by Inter as "HANDLE_HYPERLINK_R". + +To say link (T - hyperlink tag): + (- MakeTaggedHyperlink({T}); -). + +To say link (T - hyperlink tag) for/of/with (V - value of kind K): + (- MakeTaggedHyperlink({T}, {-by-reference:V}, {-strong-kind:K}); -). + +To say end link: + (- if (Cached_Glk_Gestalts-->gestalt_Hyperlinks) { glk_set_hyperlink(0); } -). + +To decide what K is hyperlink value as a/an (name of kind of value K): + (- (hyperlink_value) -). + +@ And some built-in hyperlink tags: + +- A rule hyperlink runs a rule when clicked; that in turn allows you to run any other code you like. +- A keypress hyperlink converts a hyperlink event into a character event, for the specified unicode character. + += + +Rule hyperlink is a hyperlink tag. + +To say link (R - rule): + (- MakeTaggedHyperlink((+ rule hyperlink +), {-by-reference:R}, RULE_TY); -). + +Hyperlink handling rule for a rule hyperlink (this is the rule hyperlink rule): + follow hyperlink value as a rule; + +Keypress hyperlink is a hyperlink tag. + +To say link (C - unicode character): + (- MakeTaggedHyperlink((+ keypress hyperlink +), {-by-reference:C}, UNICODE_CHARACTER_TY); -). + +Hyperlink handling rule for a keypress hyperlink (this is the keypress hyperlink rule): + replace current event with a character event with (hyperlink value as a unicode character) in (window of the current glk event initialiser); + @h Suspending input. These properties and phrases allow the author to suspend and resume input requests. @@ -203,8 +252,6 @@ Chapter - Suspending and resuming input A glk window has a text input status. The text input status property translates into Inter as "text_input_status". -A glk window can be requesting hyperlink input. -The requesting hyperlink input property translates into Inter as "requesting_hyperlink". A glk window can be requesting mouse input. The requesting mouse input property translates into Inter as "requesting_mouse". diff --git a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Miscellaneous Definitions.w b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Miscellaneous Definitions.w index b10cfa947a..d139842805 100644 --- a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Miscellaneous Definitions.w +++ b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Miscellaneous Definitions.w @@ -154,10 +154,13 @@ Section - Startup C (for Glulx only) The start capturing startup text rule is listed first in the before starting the virtual machine rules. [1st] The start capturing startup text rule translates into Inter as "CAPTURE_STARTUP_TEXT_R". +The calculate hyperlink tag width rule is listed in the before starting the virtual machine rules. [6th] +The calculate hyperlink tag width rule translates into Inter as "CALCULATE_HYPERLINK_TAG_WIDTH_R". + @ These rules now set up the built in sound channels and windows. = -The set default stylehints rule is listed in the before starting the virtual machine rules. [6th] +The set default stylehints rule is listed in the before starting the virtual machine rules. [7th] The set default stylehints rule translates into Inter as "SET_DEFAULT_STYLEHINTS_R". The sound channel initialisation rule is listed in the for starting the virtual machine rules. diff --git a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Phrase Definitions.w b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Phrase Definitions.w index 52fe6be4d8..ad25547408 100644 --- a/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Phrase Definitions.w +++ b/inform7/Internal/Extensions/Graham Nelson/Basic Inform.i7xd/Source/Sections/Phrase Definitions.w @@ -1845,6 +1845,9 @@ To say (C - RGB colour) letters: To set the background colour/color/-- to (C - RGB colour): (- VM_SetWindowColours(BASIC_COLOUR_CURRENT, {C}); -). +To decide what RGB colour is (C - basic colour) as a RGB colour: + (- {C} -). + @ Some basic window phrases, which are supported by both the Z-Machine and Glulx. (See the Glk Foundations for Glk-specific phrases.) @@ -2043,4 +2046,4 @@ Chapter 11 - Use Options Section 1 - Numerical Value To decide what number is the numerical value of (U - a use option): - (- USE_OPTION_VALUES-->({U}) -). + (- USE_OPTION_VALUES-->({U}) -). \ No newline at end of file diff --git a/inform7/Internal/Extensions/Graham Nelson/English Language.i7xd/Materials/Languages/English/Index.txt b/inform7/Internal/Extensions/Graham Nelson/English Language.i7xd/Materials/Languages/English/Index.txt index 15f78fa26f..c866bf37ab 100644 --- a/inform7/Internal/Extensions/Graham Nelson/English Language.i7xd/Materials/Languages/English/Index.txt +++ b/inform7/Internal/Extensions/Graham Nelson/English Language.i7xd/Materials/Languages/English/Index.txt @@ -314,6 +314,7 @@ %Index.Elements.St.IdentifySchannelsRules = Identify glk sound channels rules %Index.Elements.St.GlkObjectUpdatingRules = Glk object updating rules %Index.Elements.St.GlkEventHandlingRules = Glk event handling rules +%Index.Elements.St.HyperlinkHandlingRules = Hyperlink handling rules %Index.Elements.St.CheckRules = Check rules are tied to specific actions, and there are too many to index here. diff --git a/inter/index-module/Chapter 3/Standards Element.w b/inter/index-module/Chapter 3/Standards Element.w index c272c25d3f..b539ab9d05 100644 --- a/inter/index-module/Chapter 3/Standards Element.w +++ b/inter/index-module/Chapter 3/Standards Element.w @@ -57,6 +57,8 @@ void StandardsElement::render(OUTPUT_STREAM, index_session *session) { IndexRules::find_rulebook(inv, I"GLK_OBJECT_UPDATING_RB"), NULL, 1, TRUE, session); IndexRules::rulebook_box(OUT, inv, I"Index.Elements.St.GlkEventHandlingRules", NULL, IndexRules::find_rulebook(inv, I"GLK_EVENT_HANDLING_RB"), NULL, 1, TRUE, session); + IndexRules::rulebook_box(OUT, inv, I"Index.Elements.St.HyperlinkHandlingRules", NULL, + IndexRules::find_rulebook(inv, I"HYPERLINK_HANDLING_RB"), NULL, 1, TRUE, session); @ = StandardsElement::subhead(OUT, LD,