Files
cheats-updater/lib/borealis/library/include/borealis/view.hpp
2026-03-05 20:18:29 +01:00

423 lines
10 KiB
C++

/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019-2020 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <libretro-common/features/features_cpu.h>
#include <stdio.h>
#include <borealis/actions.hpp>
#include <borealis/event.hpp>
#include <borealis/frame_context.hpp>
#include <functional>
#include <map>
#include <string>
#include <vector>
namespace brls
{
// The animation to play when
// pushing or popping a view
// (implemented in Application)
enum class ViewAnimation
{
FADE, // the old view fades away and the new one fades in
SLIDE_LEFT, // the old view slides out to the left and the new one slides in from the right
SLIDE_RIGHT // inverted SLIDE_LEFT
};
// Focus direction when navigating
enum class FocusDirection
{
UP,
DOWN,
LEFT,
RIGHT
};
// View background
enum class ViewBackground
{
NONE,
SIDEBAR,
DEBUG,
BACKDROP
};
enum class ViewType
{
VIEW,
SIDEBARITEM,
};
extern NVGcolor transparent;
class View;
typedef Event<View*> GenericEvent;
typedef Event<> VoidEvent;
// Superclass for all the other views
// Lifecycle of a view is :
// new -> [willAppear -> willDisappear] -> delete
//
// Users have do to the new, the rest of the lifecycle is taken
// care of by the library
//
// willAppear and willDisappear can be called zero or multiple times
// before deletion (in case of a TabLayout for instance)
class View
{
private:
ViewBackground background = ViewBackground::NONE;
void drawBackground(NVGcontext* vg, FrameContext* ctx, Style* style);
void drawHighlight(NVGcontext* vg, Theme* theme, float alpha, Style* style, bool background);
float highlightAlpha = 0.0f;
float clickAnimationAlpha = 0.0f;
bool dirty = true;
bool highlightShaking = false;
retro_time_t highlightShakeStart;
FocusDirection highlightShakeDirection;
float highlightShakeAmplitude;
bool fadeIn = false; // is the fade in animation running?
bool forceTranslucent = false;
Theme* themeOverride = nullptr;
bool hidden = false;
std::vector<Action> actions;
ViewType viewType = ViewType::VIEW;
/**
* Parent user data, typically the index of the view
* in the internal layout structure
*/
void* parentUserdata = nullptr;
protected:
int x = 0;
int y = 0;
unsigned width = 0;
unsigned height = 0;
float collapseState = 1.0f;
bool focused = false;
View* parent = nullptr;
GenericEvent focusEvent;
virtual unsigned getShowAnimationDuration(ViewAnimation animation);
virtual void getHighlightInsets(unsigned* top, unsigned* right, unsigned* bottom, unsigned* left)
{
*top = 0;
*right = 0;
*bottom = 0;
*left = 0;
}
virtual void getHighlightMetrics(Style* style, float* cornerRadius)
{
*cornerRadius = style->Highlight.cornerRadius;
}
virtual bool isHighlightBackgroundEnabled()
{
return true;
}
// Helper functions to apply this view's alpha to a color
NVGcolor a(NVGcolor color);
NVGpaint a(NVGpaint paint);
NVGcolor RGB(unsigned r, unsigned g, unsigned b)
{
return this->a(nvgRGB(r, g, b));
}
NVGcolor RGBA(unsigned r, unsigned g, unsigned b, unsigned a)
{
return this->a(nvgRGBA(r, g, b, a));
}
NVGcolor RGBf(float r, float g, float b)
{
return this->a(nvgRGBf(r, g, b));
}
NVGcolor RGBAf(float r, float g, float b, float a)
{
return this->a(nvgRGBAf(r, g, b, a));
}
/**
* Should the hint alpha be animated when
* pushing the view?
*/
virtual bool animateHint()
{
return false;
}
public:
void setBoundaries(int x, int y, unsigned width, unsigned height);
void setBackground(ViewBackground background);
void setWidth(unsigned width);
void setHeight(unsigned height);
void shakeHighlight(FocusDirection direction);
int getX();
int getY();
unsigned getWidth();
unsigned getHeight(bool includeCollapse = true);
void setForceTranslucent(bool translucent);
void setParent(View* parent, void* parentUserdata = nullptr);
View* getParent();
bool hasParent();
void* getParentUserData();
void registerAction(std::string hintText, Key key, ActionListener actionListener, bool hidden = false);
void updateActionHint(Key key, std::string hintText);
void setActionAvailable(Key key, bool available);
virtual void playClickAnimation();
std::string describe() const { return typeid(*this).name(); }
const std::vector<Action>& getActions()
{
return this->actions;
}
virtual ViewType getViewType()
{
return this->viewType;
}
/**
* Called each frame
* Do not override it to draw your view,
* override draw() instead
*/
virtual void frame(FrameContext* ctx);
/**
* Called by frame() to draw
* the view onscreen
*/
virtual void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) = 0;
/**
* Triggered when the view has been
* resized and needs to layout its
* children
*/
virtual void layout(NVGcontext* vg, Style* style, FontStash* stash)
{
// Nothing to do
}
/**
* Called when the view will appear
* on screen, before or after layout()
*
* Can be called if the view has
* already appeared, so be careful
*/
virtual void willAppear(bool resetState = false)
{
// Nothing to do
}
/**
* Called when the view will disappear
* from the screen
*
* Can be called if the view has
* already disappeared, so be careful
*/
virtual void willDisappear(bool resetState = false)
{
// Nothing to do
}
/**
* Called when the show() animation (fade in)
* ends
*/
virtual void onShowAnimationEnd() {};
/**
* Shows the view (fade in animation)
*
* Called once when the view is
* pushed to the view stack
*
* Not recursive
*/
virtual void show(std::function<void(void)> cb, bool animate = true, ViewAnimation animation = ViewAnimation::FADE);
/**
* Hides the view in a collapse animation
*/
void collapse(bool animated = true);
bool isCollapsed();
/**
* Shows the view in a expand animation (opposite
* of collapse)
*/
void expand(bool animated = true);
/**
* Hides the view (fade out animation)
*
* Called if another view is pushed
* on top of this one
*
* Not recursive
*/
virtual void hide(std::function<void(void)> cb, bool animated = true, ViewAnimation animation = ViewAnimation::FADE);
bool isHidden();
/**
* Calls layout() on next frame
* unless immediate is true in which case
* it's called immediately
*/
void invalidate(bool immediate = false);
/**
* Is this view translucent?
*
* If you override it please return
* <value> || View::isTranslucent()
* to keep the fadeIn transition
*/
virtual bool isTranslucent()
{
return fadeIn || forceTranslucent;
}
bool isFocused();
/**
* Returns the default view to focus when focusing this view
* Typically the view itself or one of its children
*
* Returning nullptr means that the view is not focusable
* (and neither are its children)
*
* When pressing a key, the flow is :
* 1. starting from the currently focused view's parent, traverse the tree upwards and
* repeatidly call getNextFocus() on every view until we find a next view to focus or meet the end of the tree
* 2. if a view is found, getNextFocus() will internally call getDefaultFocus() for the selected child
* 3. give focus to the result, if it exists
*/
virtual View* getDefaultFocus()
{
return nullptr;
}
/**
* Returns the next view to focus given the requested direction
* and the currently focused view (as parent user data)
*
* Returning nullptr means that there is no next view to focus
* in that direction - getNextFocus will then be called on our
* parent if any
*/
virtual View* getNextFocus(FocusDirection direction, View* currentView)
{
return nullptr;
}
/**
* Fired when focus is gained
*/
virtual void onFocusGained();
/**
* Fired when focus is lost
*/
virtual void onFocusLost();
/**
* Fired when focus is gained on one of this view's children
*/
virtual void onChildFocusGained(View* child)
{
if (this->hasParent())
this->getParent()->onChildFocusGained(this);
}
/**
* Fired when focus is gained on one of this view's children
*/
virtual void onChildFocusLost(View* child)
{
if (this->hasParent())
this->getParent()->onChildFocusLost(this);
}
/**
* Fired when the window size changes
* Not guaranteed to be called before or after layout()
*/
virtual void onWindowSizeChanged()
{
// Nothing by default
}
GenericEvent* getFocusEvent();
float alpha = 1.0f;
virtual float getAlpha(bool child = false);
/**
* Forces this view and its children to use
* the specified theme variant
*/
void overrideThemeVariant(Theme* newTheme);
virtual ~View();
};
} // namespace brls