Add Borealis GUI for patch extraction on Switch.
All checks were successful
Build NRO / build (push) Successful in 1m48s
All checks were successful
Build NRO / build (push) Successful in 1m48s
Replace the console UI with a Borealis-based flow, bundle ROMFS assets and borealis as a submodule, and apply small upstream patches at build time. Self-delete runs after romfsExit on quit so the NRO can be removed like the old console build.
This commit is contained in:
383
patches/borealis-applet-frame-hints.patch
Normal file
383
patches/borealis-applet-frame-hints.patch
Normal file
@@ -0,0 +1,383 @@
|
||||
diff --git a/library/include/borealis/views/applet_frame.hpp b/library/include/borealis/views/applet_frame.hpp
|
||||
index 1402928..beacd1a 100644
|
||||
--- a/library/include/borealis/views/applet_frame.hpp
|
||||
+++ b/library/include/borealis/views/applet_frame.hpp
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <borealis/core/bind.hpp>
|
||||
#include <borealis/core/box.hpp>
|
||||
+#include <borealis/core/event.hpp>
|
||||
#include <borealis/views/image.hpp>
|
||||
#include <borealis/views/label.hpp>
|
||||
|
||||
@@ -30,6 +31,7 @@ class AppletFrame : public Box
|
||||
{
|
||||
public:
|
||||
AppletFrame();
|
||||
+ ~AppletFrame() override;
|
||||
|
||||
void handleXMLElement(tinyxml2::XMLElement* element) override;
|
||||
|
||||
@@ -48,8 +50,20 @@ class AppletFrame : public Box
|
||||
static View* create();
|
||||
|
||||
private:
|
||||
+ void updateFooterHints();
|
||||
+ void clearHintBox(Box* box);
|
||||
+ void addHintItem(Box* box, const Action& action, float spacingAfter);
|
||||
+
|
||||
BRLS_BIND(Label, title, "brls/applet_frame/title_label");
|
||||
BRLS_BIND(Image, icon, "brls/applet_frame/title_icon");
|
||||
+ BRLS_BIND(Box, footerHintRight, "brls/applet_frame/footer_hint_right");
|
||||
+ BRLS_BIND(Box, footerHintLeft, "brls/applet_frame/footer_hint_left");
|
||||
+
|
||||
+ GenericEvent::Subscription focusSubscription;
|
||||
+ VoidEvent::Subscription hintsSubscription;
|
||||
+
|
||||
+ int switchFont = FONT_INVALID;
|
||||
+ int regularFont = FONT_INVALID;
|
||||
|
||||
protected:
|
||||
View* contentView = nullptr;
|
||||
diff --git a/library/include/borealis/views/label.hpp b/library/include/borealis/views/label.hpp
|
||||
index 3e1ccef..797d328 100644
|
||||
--- a/library/include/borealis/views/label.hpp
|
||||
+++ b/library/include/borealis/views/label.hpp
|
||||
@@ -85,6 +85,7 @@ class Label : public View
|
||||
void setVerticalAlign(VerticalAlign align);
|
||||
|
||||
void setFontSize(float value);
|
||||
+ void setFontFace(int fontFace);
|
||||
void setLineHeight(float value);
|
||||
void setTextColor(NVGcolor color);
|
||||
|
||||
diff --git a/library/lib/views/applet_frame.cpp b/library/lib/views/applet_frame.cpp
|
||||
index f9f47dc..11b8cd6 100644
|
||||
--- a/library/lib/views/applet_frame.cpp
|
||||
+++ b/library/lib/views/applet_frame.cpp
|
||||
@@ -15,6 +15,11 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
+#include <algorithm>
|
||||
+#include <set>
|
||||
+
|
||||
+#include <borealis/core/application.hpp>
|
||||
+#include <borealis/core/font.hpp>
|
||||
#include <borealis/core/logger.hpp>
|
||||
#include <borealis/core/util.hpp>
|
||||
#include <borealis/views/applet_frame.hpp>
|
||||
@@ -22,6 +27,73 @@
|
||||
namespace brls
|
||||
{
|
||||
|
||||
+namespace
|
||||
+{
|
||||
+
|
||||
+constexpr float HINT_FONT_SIZE = 22.0f;
|
||||
+constexpr float HINT_SPACING = 30.0f;
|
||||
+constexpr float HINT_ICON_GAP = 4.0f;
|
||||
+
|
||||
+const char* getButtonIcon(ControllerButton button)
|
||||
+{
|
||||
+ switch (button)
|
||||
+ {
|
||||
+ case BUTTON_A:
|
||||
+ return "\uE0E0";
|
||||
+ case BUTTON_B:
|
||||
+ return "\uE0E1";
|
||||
+ case BUTTON_X:
|
||||
+ return "\uE0E2";
|
||||
+ case BUTTON_Y:
|
||||
+ return "\uE0E3";
|
||||
+ case BUTTON_START:
|
||||
+ return "\uE0EF";
|
||||
+ case BUTTON_BACK:
|
||||
+ return "\uE0F0";
|
||||
+ case BUTTON_UP:
|
||||
+ return "\uE0EB";
|
||||
+ case BUTTON_DOWN:
|
||||
+ return "\uE0EC";
|
||||
+ case BUTTON_LEFT:
|
||||
+ return "\uE0ED";
|
||||
+ case BUTTON_RIGHT:
|
||||
+ return "\uE0EE";
|
||||
+ default:
|
||||
+ return "\uE152";
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+std::string getButtonHintText(const Action& action)
|
||||
+{
|
||||
+ if (!action.hintText.empty())
|
||||
+ return action.hintText;
|
||||
+
|
||||
+ switch (action.button)
|
||||
+ {
|
||||
+ case BUTTON_A:
|
||||
+ return "Ok";
|
||||
+ case BUTTON_B:
|
||||
+ return "Zurück";
|
||||
+ case BUTTON_START:
|
||||
+ return "Beenden";
|
||||
+ default:
|
||||
+ return "";
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+bool actionsSort(const Action& a, const Action& b)
|
||||
+{
|
||||
+ if (a.button == BUTTON_START)
|
||||
+ return true;
|
||||
+ if (b.button == BUTTON_A)
|
||||
+ return true;
|
||||
+ if (b.button == BUTTON_B && a.button != BUTTON_A)
|
||||
+ return true;
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
const std::string appletFrameXML = R"xml(
|
||||
<brls:Box
|
||||
width="auto"
|
||||
@@ -36,9 +108,9 @@ const std::string appletFrameXML = R"xml(
|
||||
axis="row"
|
||||
paddingTop="@style/brls/applet_frame/header_padding_top_bottom"
|
||||
paddingBottom="@style/brls/applet_frame/header_padding_top_bottom"
|
||||
- paddingLeft="@style/brls/applet_frame/header_padding_sides"
|
||||
+ paddingLeft="26px"
|
||||
paddingRight="@style/brls/applet_frame/header_padding_sides"
|
||||
- marginLeft="@style/brls/applet_frame/padding_sides"
|
||||
+ marginLeft="22px"
|
||||
marginRight="@style/brls/applet_frame/padding_sides"
|
||||
lineColor="@theme/brls/applet_frame/separator"
|
||||
lineBottom="1px">
|
||||
@@ -61,16 +133,12 @@ const std::string appletFrameXML = R"xml(
|
||||
|
||||
<!-- Content will be injected here with grow="1.0" -->
|
||||
|
||||
- <!--
|
||||
- Footer
|
||||
- Direction inverted so that the bottom left text can be
|
||||
- set to visibility="gone" without affecting the hint
|
||||
- -->
|
||||
+ <!-- Footer -->
|
||||
<brls:Box
|
||||
width="auto"
|
||||
height="@style/brls/applet_frame/footer_height"
|
||||
axis="row"
|
||||
- direction="rightToLeft"
|
||||
+ direction="leftToRight"
|
||||
paddingLeft="@style/brls/applet_frame/footer_padding_sides"
|
||||
paddingRight="@style/brls/applet_frame/footer_padding_sides"
|
||||
paddingTop="@style/brls/applet_frame/footer_padding_top_bottom"
|
||||
@@ -81,15 +149,25 @@ const std::string appletFrameXML = R"xml(
|
||||
lineTop="1px"
|
||||
justifyContent="spaceBetween" >
|
||||
|
||||
- <brls:Rectangle
|
||||
- width="272px"
|
||||
+ <brls:Box
|
||||
+ id="brls/applet_frame/footer_hint_left"
|
||||
+ width="auto"
|
||||
height="auto"
|
||||
- color="#FF0000" />
|
||||
+ axis="row"
|
||||
+ direction="leftToRight"
|
||||
+ justifyContent="flexStart"
|
||||
+ alignItems="center"
|
||||
+ visibility="gone" />
|
||||
|
||||
- <brls:Rectangle
|
||||
- width="75px"
|
||||
+ <brls:Box
|
||||
+ id="brls/applet_frame/footer_hint_right"
|
||||
+ width="auto"
|
||||
height="auto"
|
||||
- color="#FF00FF" />
|
||||
+ grow="1.0"
|
||||
+ axis="row"
|
||||
+ direction="leftToRight"
|
||||
+ justifyContent="flexEnd"
|
||||
+ alignItems="center" />
|
||||
|
||||
</brls:Box>
|
||||
|
||||
@@ -109,6 +187,141 @@ AppletFrame::AppletFrame()
|
||||
});
|
||||
|
||||
this->forwardXMLAttribute("iconInterpolation", this->icon, "interpolation");
|
||||
+
|
||||
+ this->switchFont = Application::getFont(FONT_SWITCH_ICONS);
|
||||
+ this->regularFont = Application::getFont(FONT_REGULAR);
|
||||
+
|
||||
+ this->focusSubscription = Application::getGlobalFocusChangeEvent()->subscribe([this](View*) {
|
||||
+ this->updateFooterHints();
|
||||
+ });
|
||||
+
|
||||
+ this->hintsSubscription = Application::getGlobalHintsUpdateEvent()->subscribe([this]() {
|
||||
+ this->updateFooterHints();
|
||||
+ });
|
||||
+
|
||||
+ this->updateFooterHints();
|
||||
+}
|
||||
+
|
||||
+AppletFrame::~AppletFrame()
|
||||
+{
|
||||
+ Application::getGlobalFocusChangeEvent()->unsubscribe(this->focusSubscription);
|
||||
+ Application::getGlobalHintsUpdateEvent()->unsubscribe(this->hintsSubscription);
|
||||
+}
|
||||
+
|
||||
+void AppletFrame::clearHintBox(Box* box)
|
||||
+{
|
||||
+ if (!box)
|
||||
+ return;
|
||||
+
|
||||
+ std::vector<View*> children = box->getChildren();
|
||||
+ while (!children.empty())
|
||||
+ {
|
||||
+ View* child = children.back();
|
||||
+ box->removeView(child);
|
||||
+ children.pop_back();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void AppletFrame::addHintItem(Box* box, const Action& action, float spacingAfter)
|
||||
+{
|
||||
+ const std::string hintText = getButtonHintText(action);
|
||||
+ if (hintText.empty())
|
||||
+ return;
|
||||
+
|
||||
+ Box* item = new Box(Axis::ROW);
|
||||
+ item->setDirection(Direction::LEFT_TO_RIGHT);
|
||||
+ item->setAlignItems(AlignItems::CENTER);
|
||||
+ if (spacingAfter > 0.0f)
|
||||
+ item->setMarginRight(spacingAfter);
|
||||
+
|
||||
+ Label* icon = new Label();
|
||||
+ icon->setText(getButtonIcon(action.button));
|
||||
+ icon->setFontSize(HINT_FONT_SIZE);
|
||||
+ icon->setSingleLine(true);
|
||||
+ if (this->switchFont != FONT_INVALID)
|
||||
+ icon->setFontFace(this->switchFont);
|
||||
+
|
||||
+ Label* text = new Label();
|
||||
+ text->setText(hintText);
|
||||
+ text->setFontSize(HINT_FONT_SIZE);
|
||||
+ text->setSingleLine(true);
|
||||
+ text->setMarginLeft(HINT_ICON_GAP);
|
||||
+ if (this->regularFont != FONT_INVALID)
|
||||
+ text->setFontFace(this->regularFont);
|
||||
+
|
||||
+ item->addView(icon);
|
||||
+ item->addView(text);
|
||||
+ box->addView(item);
|
||||
+}
|
||||
+
|
||||
+void AppletFrame::updateFooterHints()
|
||||
+{
|
||||
+ this->clearHintBox(this->footerHintRight);
|
||||
+ this->clearHintBox(this->footerHintLeft);
|
||||
+
|
||||
+ std::set<ControllerButton> addedKeys;
|
||||
+ std::vector<Action> rightActions;
|
||||
+ std::vector<Action> leftActions;
|
||||
+
|
||||
+ View* focusParent = Application::getCurrentFocus();
|
||||
+ if (!focusParent)
|
||||
+ focusParent = this->contentView;
|
||||
+
|
||||
+ while (focusParent)
|
||||
+ {
|
||||
+ for (const Action& action : focusParent->getActions())
|
||||
+ {
|
||||
+ if (action.hidden || !action.available)
|
||||
+ continue;
|
||||
+
|
||||
+ if (addedKeys.find(action.button) != addedKeys.end())
|
||||
+ continue;
|
||||
+
|
||||
+ addedKeys.insert(action.button);
|
||||
+
|
||||
+ if (action.button == BUTTON_START)
|
||||
+ leftActions.push_back(action);
|
||||
+ else
|
||||
+ rightActions.push_back(action);
|
||||
+ }
|
||||
+
|
||||
+ focusParent = focusParent->getParent();
|
||||
+ }
|
||||
+
|
||||
+ std::stable_sort(rightActions.begin(), rightActions.end(), actionsSort);
|
||||
+ std::stable_sort(leftActions.begin(), leftActions.end(), actionsSort);
|
||||
+
|
||||
+ for (size_t i = 0; i < rightActions.size(); i++)
|
||||
+ {
|
||||
+ float spacing = (i + 1 < rightActions.size()) ? HINT_SPACING : 0.0f;
|
||||
+ this->addHintItem(this->footerHintRight, rightActions[i], spacing);
|
||||
+ }
|
||||
+
|
||||
+ for (size_t i = 0; i < leftActions.size(); i++)
|
||||
+ {
|
||||
+ float spacing = (i + 1 < leftActions.size()) ? HINT_SPACING : 0.0f;
|
||||
+ this->addHintItem(this->footerHintLeft, leftActions[i], spacing);
|
||||
+ }
|
||||
+
|
||||
+ std::string* commonFooter = Application::getCommonFooter();
|
||||
+ if (commonFooter && !commonFooter->empty())
|
||||
+ {
|
||||
+ Label* text = new Label();
|
||||
+ text->setText(*commonFooter);
|
||||
+ text->setFontSize(HINT_FONT_SIZE);
|
||||
+ text->setSingleLine(true);
|
||||
+ if (!leftActions.empty())
|
||||
+ text->setMarginLeft(HINT_SPACING);
|
||||
+ if (this->regularFont != FONT_INVALID)
|
||||
+ text->setFontFace(this->regularFont);
|
||||
+ this->footerHintLeft->addView(text);
|
||||
+ }
|
||||
+
|
||||
+ const bool hasRight = !this->footerHintRight->getChildren().empty();
|
||||
+ const bool hasLeft = !this->footerHintLeft->getChildren().empty();
|
||||
+
|
||||
+ this->footerHintRight->setVisibility(hasRight ? Visibility::VISIBLE : Visibility::GONE);
|
||||
+ this->footerHintLeft->setVisibility(hasLeft ? Visibility::VISIBLE : Visibility::GONE);
|
||||
}
|
||||
|
||||
void AppletFrame::setIconFromRes(std::string name)
|
||||
@@ -132,7 +345,6 @@ void AppletFrame::setContentView(View* view)
|
||||
{
|
||||
if (this->contentView)
|
||||
{
|
||||
- // Remove the node
|
||||
this->removeView(this->contentView);
|
||||
this->contentView = nullptr;
|
||||
}
|
||||
@@ -146,6 +358,7 @@ void AppletFrame::setContentView(View* view)
|
||||
this->contentView->setGrow(1.0f);
|
||||
|
||||
this->addView(this->contentView, 1);
|
||||
+ this->updateFooterHints();
|
||||
}
|
||||
|
||||
void AppletFrame::handleXMLElement(tinyxml2::XMLElement* element)
|
||||
diff --git a/library/lib/views/label.cpp b/library/lib/views/label.cpp
|
||||
index c31d904..25e4bdf 100644
|
||||
--- a/library/lib/views/label.cpp
|
||||
+++ b/library/lib/views/label.cpp
|
||||
@@ -316,6 +316,14 @@ void Label::setFontSize(float value)
|
||||
this->invalidate();
|
||||
}
|
||||
|
||||
+void Label::setFontFace(int fontFace)
|
||||
+{
|
||||
+ if (fontFace != FONT_INVALID)
|
||||
+ this->font = fontFace;
|
||||
+
|
||||
+ this->invalidate();
|
||||
+}
|
||||
+
|
||||
void Label::setLineHeight(float value)
|
||||
{
|
||||
this->lineHeight = value;
|
||||
Reference in New Issue
Block a user