DVUI

tabIndexPrevEx

Parameters

#
event_num:?u16
?u16
tabidxs:[]dvui.TabIndex
[]dvui.TabIndex
base_tig:Id
Id
in_focus_group:bool
bool

Source

Implementation

#
pub fn tabIndexPrevEx(event_num: ?u16, tabidxs: []dvui.TabIndex, base_tig: Id, in_focus_group: bool) void {
    const cw = currentWindow();
    var widgetId = focusedWidgetId();
    var oldtab: ?u16 = null;
    var oldshadow: bool = false;
    var tig: Id = base_tig;
    var newId: ?Id = null;
    var ran_off: bool = false;
    var first: bool = true;
    outer: while (true) {
        if (widgetId != null) {
            for (tabidxs) |ti| {
                if (ti.windowId == cw.subwindows.focused_id and ti.widgetId == widgetId.?) {
                    oldtab = ti.tabIndex;
                    tig = ti.tab_index_group;
                    oldshadow = ti.in_focus_group;
                    break;
                }
            }
        }

        if (first and !in_focus_group and oldtab == null) {
            if (cw.subwindows.focused()) |sw| {
                if (sw.kb_restart_widget_id) |id| {
                    newId = id;
                    sw.kb_restart_widget_id = null;
                    break :outer;
                }
            }
        }
        first = false;

        if (ran_off and oldtab == null) {
            // We ran off the tab index group, but couldn't find the entry for
            // itself, return null.  This means we are in a focus group where
            // the tab index group we searched for is outside the focus group.
            break :outer;
        }

        ran_off = false;

        // find the last widget with a tabindex less than oldtab
        // or the last widget with highest tabindex if oldtab is null
        var newtab: u16 = 1;
        var isTig: bool = false;
        var foundFocus = false;

        for (tabidxs) |ti| {
            if (ti.windowId == cw.subwindows.focused_id and ti.tab_index_group == tig) {
                if (ti.widgetId == widgetId) {
                    foundFocus = true;

                    if (oldtab != null and newtab == oldtab.?) {
                        // use last widget before that has the same tabindex
                        // might be none before so we'll go to null
                        break;
                    }
                } else if (!ti.in_focus_group) {
                    // tabidxs is ordered by insertion, not tab index, so have to
                    // search all of them to find the highest that is below oldtab
                    if (oldtab == null or ti.tabIndex < oldtab.? or (!foundFocus and ti.tabIndex == oldtab.?)) {
                        if (ti.tabIndex >= newtab) {
                            newtab = ti.tabIndex;
                            newId = ti.widgetId;
                            isTig = ti.tab_group;
                        }
                    }
                }
            }
        }

        if (newId == null and tig != base_tig) {
            // ran off the end of the tab index group, recur starting at the
            // tab index group itself
            widgetId = tig;
            oldtab = null;
            ran_off = true;
            tig = base_tig;

            continue :outer;
        }

        if (isTig) {
            // we are moving into this tab index group
            widgetId = null;
            oldtab = null;
            tig = newId.?;
            newId = null;

            continue :outer;
        }

        break :outer;
    }

    focusWidget(newId, null, event_num);

    if (oldshadow) {
        // If we shift-tabbed from inside a focusGroup, we will always focus
        // the focusGroup itself, so do this again to focus the widget before
        // the focusGroup.
        tabIndexPrevEx(event_num, tabidxs, base_tig, false);
    }

    if (newId == null) {
        // intentionally moving to the null focus state, don't try to recover
        if (cw.subwindows.focused()) |sw| {
            sw.kb_restart_widget_id = null;
        }
    }
}