mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Move refocus logic to from TitlesTab to LayeredErrorFrame.
* Refocus logic now also takes care of updating Borealis' internal focus stack if a view has been pushed on top of the root view using a ListItem from LayeredErrorFrame. * Further modifications to Borealis are used to store a pointer to the corresponding sidebar item in LayeredErrorFrame objects. * The UI code now always uses C++-style casts. * Git commit information is now displayed next to the nxdumptool release version. * The applet mode warning is now displayed centered at the top. * Title IDs in title lists are now displayed at the right of each entry.
This commit is contained in:
parent
c683e77873
commit
c50840ec7c
6 changed files with 166 additions and 68 deletions
|
@ -31,14 +31,24 @@ namespace nxdt::views
|
|||
/* Extended class to switch between ErrorFrame and List views on demand. */
|
||||
class LayeredErrorFrame: public brls::LayerView
|
||||
{
|
||||
private:
|
||||
brls::SidebarItem *sidebar_item = nullptr;
|
||||
|
||||
protected:
|
||||
ErrorFrame *error_frame = nullptr;
|
||||
brls::List *list = nullptr;
|
||||
|
||||
void SwitchLayerView(bool use_error_frame);
|
||||
bool IsListItemFocused(void);
|
||||
|
||||
int GetFocusStackViewIndex(void);
|
||||
bool UpdateFocusStackViewAtIndex(int index, brls::View *view);
|
||||
|
||||
void SwitchLayerView(bool use_error_frame, bool update_focused_view = false, bool update_focus_stack = true);
|
||||
|
||||
public:
|
||||
LayeredErrorFrame(std::string msg = "");
|
||||
|
||||
void SetParentSidebarItem(brls::SidebarItem *sidebar_item);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 7de16249a693e187e7249404d41e0da8a5572bf6
|
||||
Subproject commit 7f70ea3dd36dcdc6ca6c01e67632452a4da6d253
|
|
@ -34,24 +34,110 @@ namespace nxdt::views
|
|||
this->addLayer(this->list);
|
||||
}
|
||||
|
||||
void LayeredErrorFrame::SwitchLayerView(bool use_error_frame)
|
||||
void LayeredErrorFrame::SetParentSidebarItem(brls::SidebarItem *sidebar_item)
|
||||
{
|
||||
int index = this->getLayerIndex();
|
||||
int new_index = (index ^ 1);
|
||||
brls::View *cur_focus = brls::Application::getCurrentFocus();
|
||||
|
||||
/* Don't proceed if we're already at the desired view layer. */
|
||||
if (index < 0 || index > 1 || (use_error_frame && index == 0) || (!use_error_frame && index == 1)) return;
|
||||
|
||||
/* Focus the sidebar if we're currently focusing an element from our List and we're about to switch to the error frame. */
|
||||
if (use_error_frame && cur_focus && cur_focus->hasParent())
|
||||
{
|
||||
brls::View *cur_focus_parent = cur_focus->getParent();
|
||||
if (cur_focus_parent && cur_focus_parent->hasParent() && cur_focus_parent->getParent() == this->list) brls::Application::onGamepadButtonPressed(GLFW_GAMEPAD_BUTTON_DPAD_LEFT, false);
|
||||
if (sidebar_item) this->sidebar_item = sidebar_item;
|
||||
}
|
||||
|
||||
/* Change layer view. */
|
||||
bool LayeredErrorFrame::IsListItemFocused(void)
|
||||
{
|
||||
brls::View *cur_view = brls::Application::getCurrentFocus();
|
||||
size_t cur_list_count = this->list->getViewsCount();
|
||||
|
||||
if (cur_list_count)
|
||||
{
|
||||
while(cur_view)
|
||||
{
|
||||
if (cur_view == this->list) return true;
|
||||
cur_view = cur_view->getParent();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int LayeredErrorFrame::GetFocusStackViewIndex(void)
|
||||
{
|
||||
size_t cur_list_count = this->list->getViewsCount();
|
||||
std::vector<brls::View*> *focus_stack = brls::Application::getFocusStack();
|
||||
|
||||
if (cur_list_count && focus_stack)
|
||||
{
|
||||
size_t focus_stack_size = focus_stack->size();
|
||||
|
||||
for(size_t i = 0; i < focus_stack_size; i++)
|
||||
{
|
||||
for(size_t j = 0; j < cur_list_count; j++)
|
||||
{
|
||||
if (this->list->getChild(j) == focus_stack->at(i)) return static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool LayeredErrorFrame::UpdateFocusStackViewAtIndex(int index, brls::View *view)
|
||||
{
|
||||
std::vector<brls::View*> *focus_stack = brls::Application::getFocusStack();
|
||||
if (!focus_stack || index < 0) return false;
|
||||
|
||||
size_t focus_stack_size = focus_stack->size();
|
||||
if (index >= static_cast<int>(focus_stack_size)) return false;
|
||||
|
||||
focus_stack->at(index) = view;
|
||||
brls::Logger::debug("Focus stack updated");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LayeredErrorFrame::SwitchLayerView(bool use_error_frame, bool update_focused_view, bool update_focus_stack)
|
||||
{
|
||||
int cur_index = this->getLayerIndex();
|
||||
int new_index = (use_error_frame ? 0 : 1);
|
||||
|
||||
size_t cur_list_count = this->list->getViewsCount();
|
||||
brls::View *first_child = nullptr;
|
||||
|
||||
int focus_stack_index = this->GetFocusStackViewIndex();
|
||||
bool focus_stack_updated = false;
|
||||
|
||||
if (cur_list_count)
|
||||
{
|
||||
/* Get pointer to the first list item. */
|
||||
first_child = this->list->getChild(0);
|
||||
|
||||
/* Update focus stack information, if needed. */
|
||||
if (update_focus_stack && focus_stack_index > -1) focus_stack_updated = this->UpdateFocusStackViewAtIndex(focus_stack_index, use_error_frame ? this->sidebar_item : first_child);
|
||||
}
|
||||
|
||||
if (!focus_stack_updated)
|
||||
{
|
||||
/* Check if the user is currently focusing a list item. */
|
||||
if (!update_focused_view) update_focused_view = this->IsListItemFocused();
|
||||
|
||||
if (update_focused_view)
|
||||
{
|
||||
/* Update focused view. */
|
||||
if (use_error_frame || !cur_list_count)
|
||||
{
|
||||
/* Move focus to the sidebar item. */
|
||||
brls::Application::giveFocus(this->sidebar_item);
|
||||
} else {
|
||||
/* Move focus to the first list item. */
|
||||
brls::Application::giveFocus(first_child);
|
||||
|
||||
/* Make sure to call willAppear() on our list to update the scrolling accordingly. */
|
||||
this->list->willAppear(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Change layer view only if the new index is different. */
|
||||
if (cur_index != new_index)
|
||||
{
|
||||
this->changeLayer(new_index);
|
||||
this->invalidate(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,12 @@ namespace nxdt::views
|
|||
{
|
||||
RootView::RootView(void) : brls::TabFrame()
|
||||
{
|
||||
int material = brls::Application::getFontStash()->material;
|
||||
|
||||
/* Set UI properties. */
|
||||
this->setTitle(APP_TITLE);
|
||||
this->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg"));
|
||||
this->setFooterText("v" APP_VERSION);
|
||||
this->setFooterText("v" APP_VERSION " (" GIT_REV ")");
|
||||
|
||||
/* Check if we're running under applet mode. */
|
||||
this->applet_mode = utilsAppletModeCheck();
|
||||
|
@ -44,20 +46,21 @@ namespace nxdt::views
|
|||
/* Create labels. */
|
||||
this->applet_mode_lbl = new brls::Label(brls::LabelStyle::HINT, "root_view/applet_mode"_i18n);
|
||||
this->applet_mode_lbl->setColor(nvgRGB(255, 0, 0));
|
||||
this->applet_mode_lbl->setFontSize(brls::Application::getStyle()->AppletFrame.titleSize);
|
||||
this->applet_mode_lbl->setParent(this);
|
||||
|
||||
this->time_lbl = new brls::Label(brls::LabelStyle::SMALL, "");
|
||||
this->time_lbl->setParent(this);
|
||||
|
||||
this->battery_icon = new brls::Label(brls::LabelStyle::SMALL, "");
|
||||
this->battery_icon->setFont(brls::Application::getFontStash()->material);
|
||||
this->battery_icon->setFont(material);
|
||||
this->battery_icon->setParent(this);
|
||||
|
||||
this->battery_percentage = new brls::Label(brls::LabelStyle::SMALL, "");
|
||||
this->battery_percentage->setParent(this);
|
||||
|
||||
this->connection_icon = new brls::Label(brls::LabelStyle::SMALL, "");
|
||||
this->connection_icon->setFont(brls::Application::getFontStash()->material);
|
||||
this->connection_icon->setFont(material);
|
||||
this->connection_icon->setParent(this);
|
||||
|
||||
this->connection_status_lbl = new brls::Label(brls::LabelStyle::SMALL, "");
|
||||
|
@ -71,21 +74,40 @@ namespace nxdt::views
|
|||
this->usb_host_task = new nxdt::tasks::UsbHostTask();
|
||||
|
||||
/* Add tabs. */
|
||||
this->addTab("root_view/tabs/gamecard"_i18n, new GameCardTab(this->gc_status_task));
|
||||
GameCardTab *gamecard_tab = new GameCardTab(this->gc_status_task);
|
||||
this->addTab("root_view/tabs/gamecard"_i18n, gamecard_tab);
|
||||
gamecard_tab->SetParentSidebarItem(static_cast<brls::SidebarItem*>(this->sidebar->getChild(this->sidebar->getViewsCount() - 1)));
|
||||
|
||||
this->addSeparator();
|
||||
this->addTab("root_view/tabs/user_titles"_i18n, new TitlesTab(this->title_task, false));
|
||||
this->addTab("root_view/tabs/system_titles"_i18n, new TitlesTab(this->title_task, true));
|
||||
|
||||
TitlesTab *user_titles_tab = new TitlesTab(this->title_task, false);
|
||||
this->addTab("root_view/tabs/user_titles"_i18n, user_titles_tab);
|
||||
user_titles_tab->SetParentSidebarItem(static_cast<brls::SidebarItem*>(this->sidebar->getChild(this->sidebar->getViewsCount() - 1)));
|
||||
|
||||
TitlesTab *system_titles_tab = new TitlesTab(this->title_task, true);
|
||||
this->addTab("root_view/tabs/system_titles"_i18n, system_titles_tab);
|
||||
system_titles_tab->SetParentSidebarItem(static_cast<brls::SidebarItem*>(this->sidebar->getChild(this->sidebar->getViewsCount() - 1)));
|
||||
|
||||
this->addSeparator();
|
||||
|
||||
this->addTab("root_view/tabs/options"_i18n, new brls::Rectangle(nvgRGB(255, 255, 0)));
|
||||
|
||||
this->addSeparator();
|
||||
|
||||
this->addTab("root_view/tabs/about"_i18n, new AboutTab());
|
||||
|
||||
/* Subscribe to status info event. */
|
||||
this->status_info_task_sub = this->status_info_task->RegisterListener([this](const nxdt::tasks::StatusInfoData *status_info_data) {
|
||||
/* Update time label. */
|
||||
bool is_am = true;
|
||||
struct tm *timeinfo = status_info_data->timeinfo;
|
||||
|
||||
u32 charge_percentage = status_info_data->charge_percentage;
|
||||
PsmChargerType charger_type = status_info_data->charger_type;
|
||||
|
||||
NifmInternetConnectionType connection_type = status_info_data->connection_type;
|
||||
char *ip_addr = status_info_data->ip_addr;
|
||||
|
||||
/* Update time label. */
|
||||
timeinfo->tm_mon++;
|
||||
timeinfo->tm_year += 1900;
|
||||
|
||||
|
@ -107,18 +129,12 @@ namespace nxdt::views
|
|||
is_am ? "AM" : "PM"));
|
||||
|
||||
/* Update battery labels. */
|
||||
u32 charge_percentage = status_info_data->charge_percentage;
|
||||
PsmChargerType charger_type = status_info_data->charger_type;
|
||||
|
||||
this->battery_icon->setText(charger_type != PsmChargerType_Unconnected ? "\uE1A3" : (charge_percentage <= 15 ? "\uE19C" : "\uE1A4"));
|
||||
this->battery_icon->setColor(charger_type != PsmChargerType_Unconnected ? nvgRGB(0, 255, 0) : (charge_percentage <= 15 ? nvgRGB(255, 0, 0) : brls::Application::getTheme()->textColor));
|
||||
|
||||
this->battery_percentage->setText(fmt::format("{}%", charge_percentage));
|
||||
|
||||
/* Update network label. */
|
||||
NifmInternetConnectionType connection_type = status_info_data->connection_type;
|
||||
char *ip_addr = status_info_data->ip_addr;
|
||||
|
||||
/* Update network labels. */
|
||||
this->connection_icon->setText(!connection_type ? "\uE195" : (connection_type == NifmInternetConnectionType_WiFi ? "\uE63E" : "\uE8BE"));
|
||||
this->connection_status_lbl->setText(ip_addr ? std::string(ip_addr) : "root_view/not_connected"_i18n);
|
||||
|
||||
|
@ -173,8 +189,8 @@ namespace nxdt::views
|
|||
/* Applet mode label. */
|
||||
this->applet_mode_lbl->invalidate(true);
|
||||
this->applet_mode_lbl->setBoundaries(
|
||||
this->x + (this->width / 4) - (this->applet_mode_lbl->getWidth() / 2),
|
||||
this->y + this->height - (style->AppletFrame.footerHeight / 2),
|
||||
this->x + (this->width - this->applet_mode_lbl->getWidth()) / 2,
|
||||
this->y + (style->AppletFrame.headerHeightRegular / 2) + style->AppletFrame.titleOffset,
|
||||
this->applet_mode_lbl->getWidth(),
|
||||
this->applet_mode_lbl->getHeight());
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace nxdt::tasks
|
|||
|
||||
/* Get network connection status. */
|
||||
u32 signal_strength = 0;
|
||||
NifmInternetConnectionStatus connection_status = (NifmInternetConnectionStatus)0;
|
||||
NifmInternetConnectionStatus connection_status = static_cast<NifmInternetConnectionStatus>(0);
|
||||
|
||||
Result rc = nifmGetInternetConnectionStatus(&(status_info_data->connection_type), &signal_strength, &connection_status);
|
||||
if (R_SUCCEEDED(rc))
|
||||
|
@ -70,7 +70,7 @@ namespace nxdt::tasks
|
|||
status_info_data->ip_addr = NULL;
|
||||
}
|
||||
} else {
|
||||
status_info_data->connection_type = (NifmInternetConnectionType)0;
|
||||
status_info_data->connection_type = static_cast<NifmInternetConnectionType>(0);
|
||||
status_info_data->ip_addr = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,14 +65,18 @@ namespace nxdt::views
|
|||
app_metadata(app_metadata),
|
||||
is_system(is_system)
|
||||
{
|
||||
brls::Style* style = brls::Application::getStyle();
|
||||
|
||||
/* Set sublabel. */
|
||||
this->subLabel = (!this->is_system ? std::string(app_metadata->lang_entry.author) : fmt::format("{:016X}", this->app_metadata->title_id));
|
||||
this->setHeight(style->List.Item.heightWithSubLabel);
|
||||
if (!this->is_system)
|
||||
{
|
||||
this->subLabel = std::string(app_metadata->lang_entry.author);
|
||||
this->setHeight(brls::Application::getStyle()->List.Item.heightWithSubLabel);
|
||||
}
|
||||
|
||||
/* Set thumbnail (if needed). */
|
||||
if (app_metadata->icon && app_metadata->icon_size) this->setThumbnail(app_metadata->icon, app_metadata->icon_size);
|
||||
|
||||
/* Set value. */
|
||||
this->setValue(fmt::format("{:016X}", this->app_metadata->title_id), false, false);
|
||||
}
|
||||
|
||||
TitlesTab::TitlesTab(nxdt::tasks::TitleTask *title_task, bool is_system) : LayeredErrorFrame("titles_tab/no_titles_available"_i18n), title_task(title_task), is_system(is_system)
|
||||
|
@ -100,39 +104,25 @@ namespace nxdt::views
|
|||
|
||||
void TitlesTab::PopulateList(const nxdt::tasks::TitleApplicationMetadataVector* app_metadata)
|
||||
{
|
||||
if (!app_metadata) return;
|
||||
|
||||
/* Block inputs while we're doing our thing. */
|
||||
brls::Application::blockInputs();
|
||||
ON_SCOPE_EXIT { brls::Application::unblockInputs(); };
|
||||
|
||||
if (!app_metadata) return;
|
||||
|
||||
bool refocus = false;
|
||||
/* Populate variables. */
|
||||
size_t app_metadata_count = app_metadata->size();
|
||||
bool update_focused_view = this->IsListItemFocused();
|
||||
int focus_stack_index = this->GetFocusStackViewIndex();
|
||||
|
||||
if (app_metadata_count)
|
||||
{
|
||||
/* Determine if we need to refocus after updating the list. */
|
||||
brls::View *cur_view = brls::Application::getCurrentFocus();
|
||||
while(cur_view)
|
||||
{
|
||||
if (cur_view == this->list)
|
||||
{
|
||||
refocus = true;
|
||||
break;
|
||||
}
|
||||
|
||||
cur_view = cur_view->getParent();
|
||||
}
|
||||
} else {
|
||||
/* If we need to, switch to the error frame *before* cleaning up our list. */
|
||||
this->SwitchLayerView(true);
|
||||
}
|
||||
/* If needed, switch to the error frame *before* cleaning up our list. */
|
||||
if (!app_metadata_count) this->SwitchLayerView(true);
|
||||
|
||||
/* Clear list. */
|
||||
this->list->clear();
|
||||
this->list->invalidate(true);
|
||||
|
||||
/* Immediately return if we have no user application metadata. */
|
||||
/* Return immediately if we have no user application metadata. */
|
||||
if (!app_metadata_count) return;
|
||||
|
||||
/* Populate list. */
|
||||
|
@ -176,15 +166,11 @@ namespace nxdt::views
|
|||
this->list->addView(title);
|
||||
}
|
||||
|
||||
/* Update focus stack, if needed. */
|
||||
if (focus_stack_index > -1) this->UpdateFocusStackViewAtIndex(focus_stack_index, this->list->getChild(0));
|
||||
|
||||
/* Switch to the list. */
|
||||
this->list->invalidate(true);
|
||||
this->SwitchLayerView(false);
|
||||
|
||||
/* Refocus, if needed. */
|
||||
if (refocus)
|
||||
{
|
||||
brls::Application::giveFocus(this->list->getChild(0));
|
||||
this->list->willAppear(true);
|
||||
}
|
||||
this->SwitchLayerView(false, update_focused_view, focus_stack_index < 0);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue