Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions src/gui/gsc_info_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,85 @@ bool GscInfoWindow::on_delete_event([[maybe_unused]] GdkEventAny* e)



bool GscInfoWindow::on_key_press_event(GdkEventKey* event)
{
// Handle Ctrl+Tab and Ctrl+Shift+Tab for tab navigation
if ( (event->state & GDK_CONTROL_MASK)
&& (event->keyval == GDK_KEY_Tab || event->keyval == GDK_KEY_ISO_Left_Tab)) {

// Helper to cycle only across visible notebook pages
auto cycle_visible_pages = [&](Gtk::Notebook* notebook) -> bool {
if (!notebook) {
return false;
}

const int n_pages = notebook->get_n_pages();
std::vector<int> visible_pages;
visible_pages.reserve(n_pages);

for (int i = 0; i < n_pages; ++i) {
if (auto* page = notebook->get_nth_page(i)) {
if (page->get_visible()) {
visible_pages.push_back(i);
}
}
}

// Need at least two visible pages to make cycling meaningful
if (visible_pages.size() <= 1) {
return false;
}

const int current_page = notebook->get_current_page();
int visible_index = 0;

auto it = std::find(visible_pages.begin(), visible_pages.end(), current_page);
if (it != visible_pages.end()) {
visible_index = static_cast<int>(std::distance(visible_pages.begin(), it));
}

int next_visible_index = 0;

// Check if Shift is also pressed for backward navigation
if (event->state & GDK_SHIFT_MASK) {
// Ctrl+Shift+Tab: go to previous visible tab
next_visible_index =
(visible_index - 1 + static_cast<int>(visible_pages.size())) %
static_cast<int>(visible_pages.size());
} else {
// Ctrl+Tab: go to next visible tab
next_visible_index =
(visible_index + 1) %
static_cast<int>(visible_pages.size());
}

notebook->set_current_page(visible_pages[next_visible_index]);
return true;
};

auto* main_notebook = lookup_widget<Gtk::Notebook*>("main_notebook");
if (main_notebook) {
// Check if we're on the Advanced tab with sub-tabs
auto* advanced_notebook = lookup_widget<Gtk::Notebook*>("advanced_notebook");
if (advanced_notebook && advanced_notebook->get_visible()) {

Copilot AI Mar 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

advanced_notebook->get_visible() reflects the widget's “visible” property, not whether the Advanced page is currently the active page in main_notebook. If Advanced has 2+ visible sub-tabs, this will consume Ctrl+Tab even when the user is on another main tab (it will change the hidden sub-tab selection and return true), so main tab switching won’t work.

Consider gating sub-tab cycling on the Advanced page being the current main_notebook page (e.g., compare main_notebook->get_nth_page(main_notebook->get_current_page()) against the advanced_tab_vbox widget / use page_num()), or check advanced_notebook->get_mapped()/is_drawable() instead of get_visible() before handling the event.

Suggested change
if (advanced_notebook && advanced_notebook->get_visible()) {
if (advanced_notebook && advanced_notebook->is_drawable()) {

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude[agent] Fix by checking whether current tab is Advanced

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b6df8fd. Now checks if Advanced tab is the current active page using page_num() before handling sub-tab cycling. This prevents Ctrl+Tab from being consumed when the user is on other main tabs.

if (cycle_visible_pages(advanced_notebook)) {
return true; // event handled
}
}

// Otherwise, cycle through main notebook tabs
if (cycle_visible_pages(main_notebook)) {
return true; // event handled
}
}
}

// Call base class handler for other keys
return Gtk::Window::on_key_press_event(event);
}



void GscInfoWindow::on_refresh_info_button_clicked()
{
this->refresh_info();
Expand Down
4 changes: 4 additions & 0 deletions src/gui/gsc_info_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ class GscInfoWindow : public AppBuilderWidget<GscInfoWindow, true> {
/// Reimplemented from Gtk::Window.
bool on_delete_event(GdkEventAny* e) override;

/// Handle key press events for keyboard navigation.
/// Reimplemented from Gtk::Window.
bool on_key_press_event(GdkEventKey* event) override;


// ---------- Other callbacks

Expand Down
Loading