Back to Terminal Gui

Command Diagrams

docfx/docs/command-diagrams.md

2.0.111.9 KB
Original Source

Level 1: DefaultActivateHandler and DefaultAcceptHandler Flow

This diagram shows the actual implementation of DefaultActivateHandler and DefaultAcceptHandler. Each handler resets dispatch state, calls xref:Terminal.Gui.ViewBase.View.RaiseActivating*/xref:Terminal.Gui.ViewBase.View.RaiseAccepting* (which runs the full Cancellable Work Pattern pipeline: OnXxx virtual → Xxx event → TryDispatchToTargetxref:Terminal.Gui.ViewBase.View.TryBubbleUp*), then decides how to complete based on the result and routing mode.

mermaid
flowchart TD
    input_a["User input (Space / LeftButtonReleased)"] --> da["DefaultActivateHandler"]
    da --> da_reset["Reset _lastDispatchOccurred = false"]
    da_reset --> ra["RaiseActivating:
 OnActivating (virtual)
 → Activating event
 → TryDispatchToTarget
 → TryBubbleUp"]

    ra --> |handled: returns true| da_disp{"_lastDispatchOccurred?
(consume-dispatch composite)"}
    da_disp --> |yes| ra_act1["RaiseActivated
(composite completion)"]
    ra_act1 --> ret_t1["return true"]
    da_disp --> |no| ret_t1

    ra --> |not handled: returns false| da_bup{"Routing == BubblingUp?"}
    da_bup --> |"yes, plain view (no dispatch target)"| ra_act2["RaiseActivated
(two-phase notification)"]
    ra_act2 --> ret_f["return false"]
    da_bup --> |"yes, relay view (has dispatch target)"| ret_f
    da_bup --> |"no (Direct)"| da_sf["SetFocus (if CanFocus)"]
    da_sf --> ra_act3["RaiseActivated
(if !_lastDispatchOccurred)"]
    ra_act3 --> ret_t2["return true"]

    input_b["User input (Enter)"] --> dac["DefaultAcceptHandler"]
    dac --> dac_reset["Reset _lastDispatchOccurred = false"]
    dac_reset --> racc["RaiseAccepting:
 OnAccepting (virtual)
 → Accepting event
 → TryDispatchToTarget
 → TryBubbleUp"]

    racc --> |handled: returns true| dac_disp{"_lastDispatchOccurred
or Bridged?"}
    dac_disp --> |yes| racc_acc1["RaiseAccepted
(composite/bridge completion)"]
    racc_acc1 --> ret_ta1["return true"]
    dac_disp --> |no| ret_ta1

    racc --> |not handled: returns false| dac_def{"!acceptWillBubble
AND DefaultAcceptView exists
(not this, not source)?"}
    dac_def --> |yes| dac_dd["DispatchDown to DefaultAcceptView
(redirected = true)"]
    dac_def --> |no| dac_bup{"BubblingUp AND
has dispatch target?"}
    dac_dd --> dac_bup
    dac_bup --> |yes| racc_acc2["RaiseAccepted → return false"]
    dac_bup --> |no| racc_acc3["RaiseAccepted"]
    racc_acc3 --> ret_bool["return redirected
or willBubble
or BubblingUp
or IAcceptTarget"]

Key Points:

Level 2: Accept Propagation with DefaultAcceptView

This diagram shows how xref:Terminal.Gui.Input.Command.Accept propagates through the view hierarchy when a xref:Terminal.Gui.Views.Dialog contains an IsDefault xref:Terminal.Gui.Views.Button. Accept bubbles from xref:Terminal.Gui.Views.TextField to xref:Terminal.Gui.Views.Dialog via xref:Terminal.Gui.ViewBase.View.TryBubbleUp* (inside xref:Terminal.Gui.ViewBase.View.RaiseAccepting*), then Dialog.DefaultAcceptHandler redirects to the IsDefault xref:Terminal.Gui.Views.Button via DispatchDown.

mermaid
flowchart TD
    input2["User input (Enter on TextField)"] --> tf["TextField.DefaultAcceptHandler"]
    tf --> tf_raise["RaiseAccepting:
 OnAccepting → Accepting
 → TryDispatchToTarget
 → TryBubbleUp"]

    tf_raise --> |"TryBubbleUp: Dialog.CommandsToBubbleUp contains Accept"| dlg_invoke["Dialog.InvokeCommand
(Accept, BubblingUp)"]

    tf_raise --> |"Accept will not bubble (fallback)"| tf_def{"TextField.DefaultAcceptView
exists?"}
    tf_def --> |yes| tf_dd["DispatchDown to
TextField.DefaultAcceptView"]
    tf_def --> |no| tf_accepted["TextField.RaiseAccepted"]

    dlg_invoke --> dlg_handler["Dialog.DefaultAcceptHandler
(Routing = BubblingUp)"]
    dlg_handler --> dlg_raise["RaiseAccepting (BubblingUp):
not handled → returns false"]
    dlg_raise --> dlg_def{"Dialog.DefaultAcceptView
= IsDefault Button?"}

    dlg_def --> |yes| dlg_dd["DispatchDown(Button, ctx)
(redirected = true)"]
    dlg_dd --> btn["Button.DefaultAcceptHandler
(Routing = DispatchingDown)"]
    btn --> btn_raise["RaiseAccepting: handled
(Button is IAcceptTarget)"]
    btn_raise --> btn_accepted["Button.RaiseAccepted → return true"]
    btn_accepted --> dlg_accepted["Dialog.RaiseAccepted
(Dialog.Accepted event fires)"]
    dlg_accepted --> dlg_return["Dialog returns true"]
    dlg_return --> tf_return["TryBubbleUp returns true
→ TextField.RaiseAccepting returns true
→ TextField returns true"]

    dlg_def --> |no| dlg_no_btn["Dialog.RaiseAccepted
(no default button)"]

Key Points:

Level 3: Complete Flow with MenuBarItem, Menu, and MenuItem

This diagram illustrates command flow in the menu system. xref:Terminal.Gui.Views.MenuBarItem (a top-level "File", "Edit" item in xref:Terminal.Gui.Views.MenuBar) extends xref:Terminal.Gui.Views.MenuItem : xref:Terminal.Gui.Views.Shortcut. xref:Terminal.Gui.Views.MenuBar extends xref:Terminal.Gui.Views.Menu : xref:Terminal.Gui.Views.Bar.

mermaid
flowchart TD
    sc_header["=== Scenario 1: HotKey Activation (Alt+F) ==="]
    sc_header --> sc_input["Alt+F pressed"]
    sc_input --> sc_hotkey["MenuBarItem.InvokeCommand(HotKey)"]
    sc_hotkey --> sc_pre["RaiseHandlingHotKey:
 OnHandlingHotKey
 → HandlingHotKey event
 → TryBubbleUp"]
    sc_pre --> |"handled: canceled"| sc_cancel["return false
(key not consumed — allows text input)"]
    sc_pre --> |"not handled"| sc_hkcmd["RaiseHotKeyCommand"]
    sc_hkcmd --> sc_activate["InvokeCommand(Activate)
(MenuBarItem override: no SetFocus before this)"]
    sc_activate --> sc_default_act["DefaultActivateHandler:
 RaiseActivating → SetFocus → RaiseActivated"]
    sc_default_act --> sc_onactivated["MenuBarItem.OnActivated:
 toggles PopoverMenuOpen"]
    sc_onactivated --> sc_show["PopoverMenu shown (PopoverMenuOpen = true)"]

    sc_show --> nav_header["=== Scenario 2: Menu Navigation (Arrow Keys) ==="]
    nav_header --> nav_input["Arrow key pressed inside Menu/PopoverMenu"]
    nav_input --> nav_activate["MenuItem.InvokeCommand(Activate)"]
    nav_activate --> nav_raise["RaiseActivating:
 OnActivating → Activating
 → TryDispatchToTarget
 → TryBubbleUp"]
    nav_raise --> |"not handled (Direct)"| nav_focus["SetFocus (MenuItem gains focus)"]
    nav_focus --> nav_activated["MenuItem.RaiseActivated"]
    nav_activated --> nav_selected["Menu.SelectedMenuItem updated
→ RaiseSelectedMenuItemChanged"]
    nav_selected --> nav_bar["Menu.OnSelectedMenuItemChanged
→ MenuBar.OnSelectedMenuItemChanged"]
    nav_bar --> nav_done["Update popover visibility if needed"]

    nav_done --> acc_header["=== Scenario 3: Accept Menu Item (Enter) ==="]
    acc_header --> acc_input["Enter pressed on focused MenuItem"]
    acc_input --> acc_raise["MenuItem.RaiseAccepting:
 OnAccepting → Accepting
 → TryDispatchToTarget → TryBubbleUp"]
    acc_raise --> |"handled: action invoked"| acc_exec["MenuItem action executed
(via OnAccepting in MenuItem)"]
    acc_exec --> acc_accepted["MenuItem.RaiseAccepted"]
    acc_accepted --> acc_bubble["Accepted propagates via
CommandBridge or CommandsToBubbleUp"]
    acc_bubble --> acc_bar["MenuBar/Menu.OnAccepted"]
    acc_bar --> acc_close["MenuBar hides popover, deactivates"]

    acc_raise --> |"has SubMenu"| acc_sub["SubMenu shown
(MenuItem.OnAccepting opens SubMenu)"]

Key Points: