Analog scrolling menu implementation completed.
This commit is contained in:
parent
df10dc43a8
commit
ad05279ae7
@ -61,12 +61,12 @@ void Menu::InitializeLoadGameWindow(){
|
|||||||
}}},
|
}}},
|
||||||
{game->KEY_SCROLL,{"Scroll Up/Down",[](MenuType type){
|
{game->KEY_SCROLL,{"Scroll Up/Down",[](MenuType type){
|
||||||
auto scrollWindow=Component<ScrollableWindowComponent>(type,"Game Files List");
|
auto scrollWindow=Component<ScrollableWindowComponent>(type,"Game Files List");
|
||||||
scrollWindow->SetScrollAmount(scrollWindow->GetScrollAmount()-vf2d{0,game->KEY_SCROLL.Analog()*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F});
|
float scrollAmt=game->KEY_SCROLL.Analog()*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F;
|
||||||
for(auto component:scrollWindow->GetComponents()){
|
|
||||||
if(geom2d::overlaps(scrollWindow->GetPos()+scrollWindow->GetSize()/2,geom2d::rect<float>{component.lock()->GetPos(),component.lock()->GetSize()})){
|
scrollWindow->SetScrollAmount(scrollWindow->GetTargetScrollAmount()-vf2d{0,game->KEY_SCROLL.Analog()*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F});
|
||||||
Menu::menus[type]->SetSelection(component);
|
|
||||||
}
|
//Height of these buttons is 48.
|
||||||
}
|
scrollWindow->IncreaseSelectionIndex(scrollAmt/48.f);
|
||||||
}}},
|
}}},
|
||||||
}
|
}
|
||||||
,{ //Button Navigation Rules
|
,{ //Button Navigation Rules
|
||||||
|
@ -288,7 +288,7 @@ void Menu::OpenMenu(MenuType menu,bool cover){
|
|||||||
if(menus[menu]->onOpenFunc){
|
if(menus[menu]->onOpenFunc){
|
||||||
Data returnData;
|
Data returnData;
|
||||||
menus[menu]->onOpenFunc(menu,returnData);
|
menus[menu]->onOpenFunc(menu,returnData);
|
||||||
menus[menu]->SetSelection(returnData);
|
menus[menu]->SetSelection(returnData,true);
|
||||||
}
|
}
|
||||||
stack.push_back(menus[menu]);
|
stack.push_back(menus[menu]);
|
||||||
}
|
}
|
||||||
@ -635,38 +635,52 @@ const std::weak_ptr<MenuComponent>Menu::GetKeySelection()const{
|
|||||||
return keyboardSelection;
|
return keyboardSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::SetSelection(std::weak_ptr<MenuComponent>button){
|
void Menu::SetSelection(std::weak_ptr<MenuComponent>button,const bool scroll,const bool reset){
|
||||||
selection=button;
|
selection=button;
|
||||||
if(navigationGroups.count(button.lock()->GetName())||
|
if(navigationGroups.count(button.lock()->GetName())||
|
||||||
!button.lock()->parentComponent.expired()&&navigationGroups.count(button.lock()->parentComponent.lock()->GetName())){
|
!button.lock()->parentComponent.expired()&&navigationGroups.count(button.lock()->parentComponent.lock()->GetName())){
|
||||||
keyboardSelection=button;
|
keyboardSelection=button;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!UsingMouseNavigation()&&!button.lock()->parentComponent.expired()){
|
if(scroll&&!UsingMouseNavigation()&&!button.lock()->parentComponent.expired()){
|
||||||
auto scrollWindow=button.lock()->parentComponent.lock();
|
auto scrollWindow=button.lock()->parentComponent.lock();
|
||||||
scrollWindow->HandleOutsideDisabledButtonSelection(Menu::menus[button.lock()->parentMenu]->components[button.lock()->GetName()]);
|
scrollWindow->HandleOutsideDisabledButtonSelection(Menu::menus[button.lock()->parentMenu]->components[button.lock()->GetName()]);
|
||||||
|
scrollWindow->selectionIndex=scrollWindow->GetComponentIndex(selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!selection.lock()->parentComponent.expired()&&reset){
|
||||||
|
auto scrollWindow=selection.lock()->parentComponent.lock();
|
||||||
|
scrollWindow->targetScrollOffset.y=0.f;
|
||||||
|
scrollWindow->selectionIndex=0.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::SetSelection(std::string_view button){
|
void Menu::SetSelection(std::string_view button,const bool scroll,const bool reset){
|
||||||
selection=Component<MenuComponent>(type,std::string(button));
|
selection=Component<MenuComponent>(type,std::string(button));
|
||||||
if(navigationGroups.count(std::string(button))||
|
if(navigationGroups.count(std::string(button))||
|
||||||
!selection.lock()->parentComponent.expired()&&navigationGroups.count(selection.lock()->parentComponent.lock()->GetName())){
|
!selection.lock()->parentComponent.expired()&&navigationGroups.count(selection.lock()->parentComponent.lock()->GetName())){
|
||||||
keyboardSelection=selection;
|
keyboardSelection=selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!UsingMouseNavigation()&&!selection.lock()->parentComponent.expired()){
|
if(scroll&&!UsingMouseNavigation()&&!selection.lock()->parentComponent.expired()){
|
||||||
auto scrollWindow=selection.lock()->parentComponent.lock();
|
auto scrollWindow=selection.lock()->parentComponent.lock();
|
||||||
scrollWindow->HandleOutsideDisabledButtonSelection(Menu::menus[selection.lock()->parentMenu]->components[selection.lock()->GetName()]);
|
scrollWindow->HandleOutsideDisabledButtonSelection(Menu::menus[selection.lock()->parentMenu]->components[selection.lock()->GetName()]);
|
||||||
|
scrollWindow->selectionIndex=scrollWindow->GetComponentIndex(selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!selection.lock()->parentComponent.expired()&&reset){
|
||||||
|
auto scrollWindow=selection.lock()->parentComponent.lock();
|
||||||
|
scrollWindow->targetScrollOffset.y=0.f;
|
||||||
|
scrollWindow->selectionIndex=0.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::SetSelection(std::variant<std::string,std::weak_ptr<MenuComponent>>button){
|
void Menu::SetSelection(std::variant<std::string,std::weak_ptr<MenuComponent>>button,const bool reset){
|
||||||
if(std::holds_alternative<std::string>(button)){
|
if(std::holds_alternative<std::string>(button)){
|
||||||
SetSelection(std::string_view(std::get<std::string>(button)));
|
SetSelection(std::string_view(std::get<std::string>(button)),true,reset);
|
||||||
}else
|
}else
|
||||||
if(std::holds_alternative<std::weak_ptr<MenuComponent>>(button)){
|
if(std::holds_alternative<std::weak_ptr<MenuComponent>>(button)){
|
||||||
SetSelection(std::get<std::weak_ptr<MenuComponent>>(button));
|
SetSelection(std::get<std::weak_ptr<MenuComponent>>(button),true,reset);
|
||||||
}else{
|
}else{
|
||||||
ERR("WARNING! Specified menu opening function does not hold neither a string nor a pointer to a component to use!");
|
ERR("WARNING! Specified menu opening function does not hold neither a string nor a pointer to a component to use!");
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,7 @@ class Menu:public IAttributable{
|
|||||||
float buttonHoldTime=0;
|
float buttonHoldTime=0;
|
||||||
static vi2d lastActiveMousePos;
|
static vi2d lastActiveMousePos;
|
||||||
int componentCount=0;
|
int componentCount=0;
|
||||||
|
float componentSelectionIndex=0.f;
|
||||||
|
|
||||||
std::unique_ptr<MenuComponent>draggingComponent;
|
std::unique_ptr<MenuComponent>draggingComponent;
|
||||||
ViewPort window;
|
ViewPort window;
|
||||||
@ -217,11 +218,13 @@ public:
|
|||||||
static Renderable&GetPatchPart(int x,int y);
|
static Renderable&GetPatchPart(int x,int y);
|
||||||
void RecalculateComponentCount();
|
void RecalculateComponentCount();
|
||||||
|
|
||||||
void SetSelection(std::string_view button);
|
void SetSelection(std::string_view button,const bool scroll=true,const bool reset=false); // Use the reset parameter when a window is opening up, as this will cause the window now to scroll to its previous target.
|
||||||
void SetSelection(std::weak_ptr<MenuComponent>button);
|
void SetSelection(std::weak_ptr<MenuComponent>button,const bool scroll=true,const bool reset=false); // Use the reset parameter when a window is opening up, as this will cause the window now to scroll to its previous target.
|
||||||
void SetSelection(std::variant<std::string,std::weak_ptr<MenuComponent>>button);
|
void SetSelection(std::variant<std::string,std::weak_ptr<MenuComponent>>button,const bool reset=false); // Use the reset parameter when a window is opening up, as this will cause the window now to scroll to its previous target.
|
||||||
const std::weak_ptr<MenuComponent>GetSelection()const;
|
const std::weak_ptr<MenuComponent>GetSelection()const;
|
||||||
const std::weak_ptr<MenuComponent>GetKeySelection()const;
|
const std::weak_ptr<MenuComponent>GetKeySelection()const;
|
||||||
|
void IncreaseSelectionIndex(const float val);
|
||||||
|
void DecreaseSelectionIndex(const float val);
|
||||||
private:
|
private:
|
||||||
Menu(vf2d pos,vf2d size);
|
Menu(vf2d pos,vf2d size);
|
||||||
static MenuType lastMenuTypeCreated;
|
static MenuType lastMenuTypeCreated;
|
||||||
|
@ -44,6 +44,7 @@ All rights reserved.
|
|||||||
using A=Attribute;
|
using A=Attribute;
|
||||||
|
|
||||||
class ScrollableWindowComponent:public MenuComponent{
|
class ScrollableWindowComponent:public MenuComponent{
|
||||||
|
friend class Menu;
|
||||||
protected:
|
protected:
|
||||||
ViewPort subWindow;
|
ViewPort subWindow;
|
||||||
std::vector<std::weak_ptr<MenuComponent>>components;
|
std::vector<std::weak_ptr<MenuComponent>>components;
|
||||||
@ -56,6 +57,8 @@ protected:
|
|||||||
float scrollBarHoverTime=0;
|
float scrollBarHoverTime=0;
|
||||||
vf2d scrollOffset{};
|
vf2d scrollOffset{};
|
||||||
vf2d targetScrollOffset{};
|
vf2d targetScrollOffset{};
|
||||||
|
float lastScrollUpdate=0.f;
|
||||||
|
float selectionIndex=0.f;
|
||||||
protected:
|
protected:
|
||||||
inline bool OnScreen(std::weak_ptr<MenuComponent>component){
|
inline bool OnScreen(std::weak_ptr<MenuComponent>component){
|
||||||
return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component.lock()->rect.pos+vf2d{2,2},component.lock()->rect.size-vf2d{2,2}});
|
return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component.lock()->rect.pos+vf2d{2,2},component.lock()->rect.size-vf2d{2,2}});
|
||||||
@ -89,14 +92,24 @@ public:
|
|||||||
virtual inline void SetScrollAmount(vf2d scrollOffset){
|
virtual inline void SetScrollAmount(vf2d scrollOffset){
|
||||||
this->targetScrollOffset=scrollOffset;
|
this->targetScrollOffset=scrollOffset;
|
||||||
}
|
}
|
||||||
virtual inline vf2d GetScrollAmount(){
|
//Use this when you need to add more scrolling offset to a previous amount as GetScrollAmount() is used to get the internal scroll offset specifically.
|
||||||
|
virtual inline vf2d GetTargetScrollAmount()const{
|
||||||
return targetScrollOffset;
|
return targetScrollOffset;
|
||||||
}
|
}
|
||||||
virtual bool GetHoverState(AiL*game,MenuComponent*child)override{
|
virtual bool GetHoverState(AiL*game,MenuComponent*child)override{
|
||||||
return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos,rect.size},game->GetMousePos())&& //Make sure the mouse is inside the parent window component first....
|
return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos,rect.size},game->GetMousePos())&& //Make sure the mouse is inside the parent window component first....
|
||||||
geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos,child->rect.size},game->GetMousePos());
|
geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos,child->rect.size},game->GetMousePos());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void IncreaseSelectionIndex(const float val){
|
||||||
|
float prevIndex=selectionIndex;
|
||||||
|
selectionIndex=std::clamp(selectionIndex+val,0.f,float(components.size()-1));
|
||||||
|
if(size_t(prevIndex)!=size_t(selectionIndex)){Menu::menus[parentMenu]->SetSelection(components[size_t(selectionIndex)],false);}
|
||||||
|
}
|
||||||
protected:
|
protected:
|
||||||
|
virtual inline vf2d GetScrollAmount()const{
|
||||||
|
return scrollOffset;
|
||||||
|
}
|
||||||
virtual inline void AfterCreate()override{
|
virtual inline void AfterCreate()override{
|
||||||
//Let's use the internal name of this component to add unique names for sub-components.
|
//Let's use the internal name of this component to add unique names for sub-components.
|
||||||
upButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+vf2d{rect.size.x-12,0}).str()+"_"+vf2d(12,12).str(),MenuComponent)(geom2d::rect<float>{rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END;
|
upButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+vf2d{rect.size.x-12,0}).str()+"_"+vf2d(12,12).str(),MenuComponent)(geom2d::rect<float>{rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END;
|
||||||
@ -116,6 +129,8 @@ protected:
|
|||||||
virtual inline void Update(AiL*game)override{
|
virtual inline void Update(AiL*game)override{
|
||||||
MenuComponent::Update(game);
|
MenuComponent::Update(game);
|
||||||
|
|
||||||
|
lastScrollUpdate=std::max(0.f,lastScrollUpdate-game->GetElapsedTime());
|
||||||
|
|
||||||
vf2d windowAbsPos=Menu::menus[parentMenu]->pos+rect.pos;
|
vf2d windowAbsPos=Menu::menus[parentMenu]->pos+rect.pos;
|
||||||
|
|
||||||
bool mouseOverScrollbar=geom2d::overlaps(geom2d::rect<float>(windowAbsPos+vf2d{rect.size.x-12,scrollBarTop+12},{12,scrollBarHeight}),game->GetMousePos());
|
bool mouseOverScrollbar=geom2d::overlaps(geom2d::rect<float>(windowAbsPos+vf2d{rect.size.x-12,scrollBarTop+12},{12,scrollBarHeight}),game->GetMousePos());
|
||||||
@ -143,10 +158,6 @@ protected:
|
|||||||
scrollBarHoverTime=std::max(scrollBarHoverTime-game->GetElapsedTime(),0.f);
|
scrollBarHoverTime=std::max(scrollBarHoverTime-game->GetElapsedTime(),0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(std::weak_ptr<MenuComponent>component:components){
|
|
||||||
component.lock()->rect.pos=component.lock()->originalPos+targetScrollOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(game->GetMouseWheel()!=0){
|
if(game->GetMouseWheel()!=0){
|
||||||
if(game->GetMouseWheel()>0){
|
if(game->GetMouseWheel()>0){
|
||||||
SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
|
SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
|
||||||
@ -157,10 +168,12 @@ protected:
|
|||||||
|
|
||||||
if(bounds.size.y-rect.size.y>0){
|
if(bounds.size.y-rect.size.y>0){
|
||||||
scrollOffset.y=std::clamp(GetScrollAmount().y,-(bounds.size.y-rect.size.y),0.f);
|
scrollOffset.y=std::clamp(GetScrollAmount().y,-(bounds.size.y-rect.size.y),0.f);
|
||||||
SetScrollAmount({GetScrollAmount().x,std::clamp(GetScrollAmount().y,-(bounds.size.y-rect.size.y),0.f)});
|
SetScrollAmount({targetScrollOffset.x,std::clamp(targetScrollOffset.y,-(bounds.size.y-rect.size.y),0.f)});
|
||||||
|
selectionIndex=std::clamp(selectionIndex,0.f,float(components.size()-1));
|
||||||
}else{
|
}else{
|
||||||
scrollOffset.y=0;
|
scrollOffset.y=0;
|
||||||
SetScrollAmount({GetScrollAmount().x,0});
|
SetScrollAmount({targetScrollOffset.x,0});
|
||||||
|
selectionIndex=std::clamp(selectionIndex,0.f,float(components.size()-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(components.begin(),components.end(),[](std::weak_ptr<MenuComponent>c1,std::weak_ptr<MenuComponent>c2){return c1.lock()->depth>c2.lock()->depth;});
|
std::sort(components.begin(),components.end(),[](std::weak_ptr<MenuComponent>c1,std::weak_ptr<MenuComponent>c2){return c1.lock()->depth>c2.lock()->depth;});
|
||||||
@ -175,6 +188,31 @@ protected:
|
|||||||
upButton.lock()->disabled=true;
|
upButton.lock()->disabled=true;
|
||||||
downButton.lock()->disabled=true;
|
downButton.lock()->disabled=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma region Move scroll offset towards target offset
|
||||||
|
if(scrollOffset.y!=targetScrollOffset.y){
|
||||||
|
if(lastScrollUpdate==0.f){
|
||||||
|
float diff=fabs(targetScrollOffset.y-scrollOffset.y);
|
||||||
|
|
||||||
|
if(targetScrollOffset.y>scrollOffset.y){
|
||||||
|
scrollOffset.y+=diff/4.f;
|
||||||
|
if(targetScrollOffset.y<scrollOffset.y){
|
||||||
|
scrollOffset.y=targetScrollOffset.y;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
scrollOffset.y-=diff/4.f;
|
||||||
|
if(targetScrollOffset.y>scrollOffset.y){
|
||||||
|
scrollOffset.y=targetScrollOffset.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::weak_ptr<MenuComponent>component:components){
|
||||||
|
component.lock()->rect.pos=component.lock()->originalPos+scrollOffset;
|
||||||
|
}
|
||||||
|
lastScrollUpdate=1/60.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma endregion
|
||||||
}
|
}
|
||||||
inline void DrawScrollbar(ViewPort&window,vf2d parentPos,bool focused){
|
inline void DrawScrollbar(ViewPort&window,vf2d parentPos,bool focused){
|
||||||
float spaceBetweenTopAndBottomArrows=rect.size.y-24;
|
float spaceBetweenTopAndBottomArrows=rect.size.y-24;
|
||||||
@ -191,6 +229,10 @@ protected:
|
|||||||
window.DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-11.75f,scrollBarTop+12},{12,scrollBarHeight},WHITE*focusedWindowColorMult);
|
window.DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-11.75f,scrollBarTop+12},{12,scrollBarHeight},WHITE*focusedWindowColorMult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline float GetComponentIndex(std::weak_ptr<MenuComponent>comp){
|
||||||
|
return float(std::distance(GetComponents().begin(),std::find_if(GetComponents().begin(),GetComponents().end(),[&](auto&component){return &*comp.lock()==&*component.lock();})));
|
||||||
|
}
|
||||||
|
|
||||||
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
|
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
|
||||||
MenuComponent::DrawDecal(window,focused);
|
MenuComponent::DrawDecal(window,focused);
|
||||||
if(border){
|
if(border){
|
||||||
|
@ -27,6 +27,8 @@ Story proofreading/correcting/storyboarding
|
|||||||
- Lock up unimplemented classes.
|
- Lock up unimplemented classes.
|
||||||
- Don't enable all stage plates normally.
|
- Don't enable all stage plates normally.
|
||||||
|
|
||||||
|
- Auto targeting for controller / keyboard.
|
||||||
|
|
||||||
A "Debug" version of the game that simply outputs all std::cout to a file as well (debug.log).
|
A "Debug" version of the game that simply outputs all std::cout to a file as well (debug.log).
|
||||||
ERR messages become just output messages in release build and won't crash the game.
|
ERR messages become just output messages in release build and won't crash the game.
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ All rights reserved.
|
|||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 3
|
#define VERSION_MINOR 3
|
||||||
#define VERSION_PATCH 0
|
#define VERSION_PATCH 0
|
||||||
#define VERSION_BUILD 6071
|
#define VERSION_BUILD 6119
|
||||||
|
|
||||||
#define stringify(a) stringify_(a)
|
#define stringify(a) stringify_(a)
|
||||||
#define stringify_(a) #a
|
#define stringify_(a) #a
|
||||||
|
Loading…
x
Reference in New Issue
Block a user