The open source repository for the action RPG game in development by Sig Productions titled 'Adventures in Lestoria'!
https://forums.lestoria.net
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
451 lines
22 KiB
451 lines
22 KiB
#pragma region License
|
|
/*
|
|
License (OLC-3)
|
|
~~~~~~~~~~~~~~~
|
|
|
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions or derivations of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions or derivative works in binary form must reproduce the above
|
|
copyright notice. This list of conditions and the following disclaimer must be
|
|
reproduced in the documentation and/or other materials provided with the distribution.
|
|
|
|
3. Neither the name of the copyright holder nor the names of its contributors may
|
|
be used to endorse or promote products derived from this software without specific
|
|
prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
SUCH DAMAGE.
|
|
|
|
Portions of this software are copyright © 2024 The FreeType
|
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
|
|
All rights reserved.
|
|
*/
|
|
#pragma endregion
|
|
#pragma once
|
|
#include "Menu.h"
|
|
#include "MenuComponent.h"
|
|
#include "AdventuresInLestoria.h"
|
|
|
|
using A=Attribute;
|
|
|
|
#define ADDSUB(key,componentType) _AddSubcomponent<componentType>(name,key,std::make_shared<componentType>
|
|
|
|
INCLUDE_game
|
|
|
|
class ScrollableWindowComponent:public MenuComponent{
|
|
friend class Menu;
|
|
protected:
|
|
ViewPort subWindow;
|
|
std::vector<std::weak_ptr<MenuComponent>>components;
|
|
std::weak_ptr<MenuComponent>upButton;
|
|
std::weak_ptr<MenuComponent>downButton;
|
|
geom2d::rect<float>bounds; //It's for the scrollbar.
|
|
std::vector<std::weak_ptr<MenuComponent>>subcomponents; //Subcomponents are anything that is created internally by another component.
|
|
float scrollBarHeight=0;
|
|
float scrollBarTop=0;
|
|
bool scrollBarSelected=false;
|
|
float scrollBarHoverTime=0;
|
|
vf2d scrollOffset{};
|
|
vf2d targetScrollOffset{};
|
|
float lastScrollUpdate=0.f;
|
|
float selectionIndex=0.f;
|
|
protected:
|
|
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}});
|
|
}
|
|
public:
|
|
inline ScrollableWindowComponent(geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
|
|
:MenuComponent(rect,"",[](MenuFuncData data){return true;},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD){
|
|
background=attributes&ComponentAttr::BACKGROUND;
|
|
border=attributes&ComponentAttr::OUTLINE;
|
|
}
|
|
virtual inline void RemoveAllComponents(){
|
|
while(components.size()>0){
|
|
RemoveButton(components.back());
|
|
}
|
|
while(subcomponents.size()>0){
|
|
std::weak_ptr<MenuComponent>button=subcomponents.back();
|
|
std::string componentName=button.lock()->GetName();
|
|
subcomponents.erase(subcomponents.end()-1);
|
|
size_t removedCount=0;
|
|
|
|
MenuType parentMenu=button.lock()->parentMenu;
|
|
|
|
removedCount+=Menu::menus[parentMenu]->components.erase(componentName);
|
|
if(removedCount!=1){
|
|
LOG("WARNING! Attempted to remove subbuttons from button listing, but not found!");
|
|
}
|
|
}
|
|
}
|
|
virtual inline void RemoveButton(std::weak_ptr<MenuComponent>button){
|
|
auto componentSearchResults=std::find_if(components.begin(),components.end(),[&](std::weak_ptr<MenuComponent>ptr){return &*ptr.lock()==&*button.lock();});
|
|
auto subcomponentSearchResults=std::find_if(subcomponents.begin(),subcomponents.end(),[&](std::weak_ptr<MenuComponent>ptr){return &*ptr.lock()==&*button.lock();});
|
|
if(componentSearchResults==components.end()&&subcomponentSearchResults==subcomponents.end())ERR("Could not find Component "<<std::quoted(button.lock()->GetName())<<" inside the component or subcomponent lists!");
|
|
if(componentSearchResults!=components.end())components.erase(componentSearchResults);
|
|
if(subcomponentSearchResults!=subcomponents.end())subcomponents.erase(subcomponentSearchResults);
|
|
size_t removedCount=0;
|
|
|
|
MenuType parentMenu=button.lock()->parentMenu;
|
|
|
|
removedCount+=Menu::menus[parentMenu]->components.erase(button.lock()->GetName());
|
|
if(removedCount!=1){
|
|
LOG("WARNING! Attempted to remove buttons from button listing, but not found!");
|
|
}
|
|
CalculateBounds();
|
|
}
|
|
virtual inline size_t GetMainComponentCount()const{
|
|
return components.size();
|
|
}
|
|
virtual inline size_t GetSubcomponentCount()const{
|
|
return subcomponents.size();
|
|
}
|
|
virtual inline void SetScrollAmount(vf2d scrollOffset){
|
|
this->targetScrollOffset=scrollOffset;
|
|
}
|
|
//Provide an amount to scroll by in units/sec.
|
|
virtual inline void Scroll(float amt){
|
|
SetScrollAmount(GetTargetScrollAmount()-vf2d{0,amt*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F});
|
|
}
|
|
//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;
|
|
}
|
|
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....
|
|
geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos,child->rect.size},game->GetMousePos());
|
|
}
|
|
|
|
inline void SetSelectionIndex(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);}
|
|
}
|
|
|
|
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:
|
|
virtual inline vf2d GetScrollAmount()const{
|
|
return scrollOffset;
|
|
}
|
|
virtual inline void AfterCreate()override{
|
|
//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;
|
|
downButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+rect.size-vf2d{12,12}).str()+"_"+vf2d(12,12).str(),MenuComponent)(geom2d::rect<float>{rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()-vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END;
|
|
subWindow=ViewPort::rectViewPort({},rect.size,Menu::menus[parentMenu]->pos+rect.pos);
|
|
if(!upButton.expired()){
|
|
if(IsEnabled()){
|
|
upButton.lock()->Enable();
|
|
}else{
|
|
upButton.lock()->Disable();
|
|
}
|
|
}
|
|
if(!downButton.expired()){
|
|
if(IsEnabled()){
|
|
downButton.lock()->Enable();
|
|
}else{
|
|
downButton.lock()->Disable();
|
|
}
|
|
}
|
|
}
|
|
virtual inline void BeforeUpdate(AiL*game)override{
|
|
MenuComponent::BeforeUpdate(game);
|
|
for(std::weak_ptr<MenuComponent>component:components){
|
|
std::shared_ptr<MenuComponent>componentPtr=component.lock();
|
|
if(componentPtr->renderInMain)ERR(std::format("WARNING! Component {} is inside a ScrollableWindowComponent but renders in main instead! Parent Component: {}",componentPtr->GetName(),GetName()));
|
|
componentPtr->_BeforeUpdate(game);
|
|
}
|
|
for(const auto&component:subcomponents){
|
|
std::shared_ptr<MenuComponent>componentPtr=component.lock();
|
|
if(componentPtr->renderInMain)ERR(std::format("WARNING! Subcomponent {} is inside a ScrollableWindowComponent but renders in main instead! Parent Component: {}",componentPtr->GetName(),GetName()));
|
|
componentPtr->_BeforeUpdate(game);
|
|
}
|
|
}
|
|
virtual inline void Update(AiL*game)override{
|
|
MenuComponent::Update(game);
|
|
|
|
lastScrollUpdate=std::max(0.f,lastScrollUpdate-game->GetElapsedTime());
|
|
|
|
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());
|
|
|
|
auto ScrollToClickedPosition=[&](){
|
|
float spaceBetweenTopAndBottomArrows=rect.size.y-24;
|
|
float viewHeight=rect.size.y;
|
|
|
|
float totalContentHeight=bounds.size.y;
|
|
if(totalContentHeight==0)totalContentHeight=1;
|
|
float scrollBarScale=(spaceBetweenTopAndBottomArrows/totalContentHeight);
|
|
//The scroll amount moves centered on the position the mouse is at.
|
|
float newScrollbarTop=(game->GetMousePos().y-windowAbsPos.y-12)-scrollBarHeight/2;
|
|
SetScrollAmount({GetScrollAmount().x,(-newScrollbarTop+1)/scrollBarScale});
|
|
};
|
|
|
|
if(mouseOverScrollbar||scrollBarSelected){
|
|
scrollBarHoverTime=std::min(scrollBarHoverTime+game->GetElapsedTime(),"ThemeGlobal.HighlightTime"_F);
|
|
if(game->GetMouse(0).bPressed&&!geom2d::contains(rect,bounds)){
|
|
scrollBarSelected=true;
|
|
Menu::menus[parentMenu]->alreadyClicked=true;
|
|
}
|
|
if(game->GetMouse(0).bReleased){
|
|
scrollBarSelected=false;
|
|
Menu::scrolling=false;
|
|
}
|
|
if(scrollBarSelected){
|
|
Menu::scrolling=true;
|
|
ScrollToClickedPosition();
|
|
}
|
|
}else{
|
|
scrollBarHoverTime=std::max(scrollBarHoverTime-game->GetElapsedTime(),0.f);
|
|
//It's possible to still scroll by clicking outside the scrollbar but in the scroll region.
|
|
if(game->GetMouse(0).bHeld&&!geom2d::contains(rect,bounds)&&
|
|
geom2d::overlaps(geom2d::rect<float>(windowAbsPos+vf2d{rect.size.x-12.f,12.f},{12.f,rect.size.y-12.f}),game->GetMousePos())){
|
|
ScrollToClickedPosition();
|
|
scrollBarSelected=true;
|
|
Menu::menus[parentMenu]->alreadyClicked=true;
|
|
}
|
|
}
|
|
|
|
if(game->GetMouseWheel()!=0){
|
|
if(game->GetMouseWheel()>0){
|
|
SetScrollAmount(GetTargetScrollAmount()+vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
|
|
}else{
|
|
SetScrollAmount(GetTargetScrollAmount()-vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
|
|
}
|
|
}
|
|
|
|
if(bounds.size.y-rect.size.y>0){
|
|
scrollOffset.y=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{
|
|
scrollOffset.y=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;});
|
|
for(std::weak_ptr<MenuComponent>component:components){
|
|
if(OnScreen(component.lock())){
|
|
component.lock()->EnableOutsideWindow();
|
|
}else{
|
|
component.lock()->DisableOutsideWindow();
|
|
}
|
|
component.lock()->_Update(game);
|
|
}
|
|
std::sort(subcomponents.begin(),subcomponents.end(),[](std::weak_ptr<MenuComponent>c1,std::weak_ptr<MenuComponent>c2){return c1.lock()->depth>c2.lock()->depth;});
|
|
for(std::weak_ptr<MenuComponent>component:subcomponents){
|
|
if(OnScreen(component.lock())){
|
|
component.lock()->EnableOutsideWindow();
|
|
}else{
|
|
component.lock()->DisableOutsideWindow();
|
|
}
|
|
component.lock()->_Update(game);
|
|
}
|
|
|
|
upButton.lock()->disable=false;
|
|
downButton.lock()->disable=false;
|
|
if(geom2d::contains(rect,bounds)){//This means we have no reason to show a scrollbar.
|
|
upButton.lock()->disable=true;
|
|
downButton.lock()->disable=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;
|
|
}
|
|
for(std::weak_ptr<MenuComponent>component:subcomponents){
|
|
component.lock()->rect.pos=component.lock()->originalPos+scrollOffset;
|
|
}
|
|
lastScrollUpdate=1/60.f;
|
|
}
|
|
}
|
|
#pragma endregion
|
|
}
|
|
inline void DrawScrollbar(ViewPort&window,vf2d parentPos,bool focused){
|
|
float spaceBetweenTopAndBottomArrows=rect.size.y-24;
|
|
float viewHeight=rect.size.y;
|
|
float totalContentHeight=bounds.size.y;
|
|
if(totalContentHeight==0)totalContentHeight=1;
|
|
float scrollBarScale=(spaceBetweenTopAndBottomArrows/totalContentHeight);
|
|
scrollBarHeight=std::min(spaceBetweenTopAndBottomArrows,viewHeight*scrollBarScale-1);
|
|
scrollBarTop=-GetScrollAmount().y*scrollBarScale+1;
|
|
|
|
float focusedWindowColorMult=(focused?1:"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
|
|
|
window.FillRectDecal(rect.pos+parentPos+vf2d{rect.size.x-12.f,scrollBarTop+12},{12,scrollBarHeight},PixelLerp(Menu::GetCurrentTheme().GetButtonCol(),Menu::GetCurrentTheme().GetHighlightCol(),scrollBarHoverTime/"ThemeGlobal.HighlightTime"_F)*focusedWindowColorMult);
|
|
window.DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-12.f,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{
|
|
MenuComponent::DrawDecal(window,focused);
|
|
if(border){
|
|
window.DrawRectDecal(rect.pos,rect.size);
|
|
}
|
|
for(std::weak_ptr<MenuComponent>component:components){
|
|
component.lock()->_DrawDecal(subWindow,focused);
|
|
}
|
|
for(std::weak_ptr<MenuComponent>component:subcomponents){
|
|
component.lock()->_DrawDecal(subWindow,focused);
|
|
}
|
|
if(!geom2d::contains(rect,bounds)){
|
|
DrawScrollbar(window,{},focused);
|
|
}
|
|
}
|
|
public:
|
|
//Calculates the bounds of all components.
|
|
inline void CalculateBounds(){
|
|
bounds={};
|
|
for(std::weak_ptr<MenuComponent>component:components){
|
|
if(component.lock()->rect.pos.x<bounds.pos.x){
|
|
float sizeIncrease=bounds.pos.x-component.lock()->rect.pos.x;
|
|
bounds.size.x+=sizeIncrease;
|
|
bounds.pos.x=component.lock()->rect.pos.x;
|
|
}
|
|
if(component.lock()->rect.right().start.x>bounds.right().start.x){
|
|
float sizeIncrease=component.lock()->rect.right().start.x-bounds.right().start.x;
|
|
bounds.size.x+=sizeIncrease;
|
|
}
|
|
if(component.lock()->rect.pos.y<bounds.pos.y){
|
|
float sizeIncrease=bounds.pos.y-component.lock()->rect.pos.y;
|
|
bounds.size.y+=sizeIncrease;
|
|
bounds.pos.y=component.lock()->rect.pos.y;
|
|
}
|
|
if(component.lock()->rect.bottom().start.y>bounds.bottom().start.y){
|
|
float sizeIncrease=component.lock()->rect.bottom().start.y-bounds.bottom().start.y;
|
|
bounds.size.y+=sizeIncrease;
|
|
}
|
|
}
|
|
for(std::weak_ptr<MenuComponent>component:subcomponents){
|
|
if(component.lock()->rect.pos.x<bounds.pos.x){
|
|
float sizeIncrease=bounds.pos.x-component.lock()->rect.pos.x;
|
|
bounds.size.x+=sizeIncrease;
|
|
bounds.pos.x=component.lock()->rect.pos.x;
|
|
}
|
|
if(component.lock()->rect.right().start.x>bounds.right().start.x){
|
|
float sizeIncrease=component.lock()->rect.right().start.x-bounds.right().start.x;
|
|
bounds.size.x+=sizeIncrease;
|
|
}
|
|
if(component.lock()->rect.pos.y<bounds.pos.y){
|
|
float sizeIncrease=bounds.pos.y-component.lock()->rect.pos.y;
|
|
bounds.size.y+=sizeIncrease;
|
|
bounds.pos.y=component.lock()->rect.pos.y;
|
|
}
|
|
if(component.lock()->rect.bottom().start.y>bounds.bottom().start.y){
|
|
float sizeIncrease=component.lock()->rect.bottom().start.y-bounds.bottom().start.y;
|
|
bounds.size.y+=sizeIncrease;
|
|
}
|
|
}
|
|
}
|
|
public:
|
|
template<class T>
|
|
std::shared_ptr<T> _AddSubcomponent(std::string parentKey,std::string key,std::shared_ptr<T>button){
|
|
if(Menu::menus[parentMenu]->components.count(key)){
|
|
ERR("WARNING! Key "<<key<<" for menu"<<parentMenu<<" already exists! Key names must be unique!")
|
|
}
|
|
|
|
subcomponents.push_back(button);
|
|
button->renderInMain=false; //Now we are in control!
|
|
button->parentComponent=DYNAMIC_POINTER_CAST<ScrollableWindowComponent>(Menu::menus[parentMenu]->components[this->GetName()]);
|
|
button->disable=disable;
|
|
|
|
CalculateBounds();
|
|
|
|
Menu::menus[parentMenu]->_AddComponent(key,button);
|
|
button->subcomponentParent=Menu::menus[parentMenu]->components.at(parentKey);
|
|
return button;
|
|
}
|
|
template<class T>
|
|
std::shared_ptr<T> _AddComponent(std::string key,std::shared_ptr<T>button){
|
|
if(Menu::menus[parentMenu]->components.count(key)){
|
|
ERR("WARNING! Key "<<key<<" for menu"<<parentMenu<<" already exists! Key names must be unique!")
|
|
}
|
|
|
|
components.push_back(button);
|
|
button->renderInMain=false; //Now we are in control!
|
|
button->parentComponent=DYNAMIC_POINTER_CAST<ScrollableWindowComponent>(Menu::menus[parentMenu]->components[this->GetName()]);
|
|
button->disable=disable;
|
|
|
|
CalculateBounds();
|
|
|
|
Menu::menus[parentMenu]->_AddComponent(key,button);
|
|
return button;
|
|
}
|
|
virtual inline bool PointWithinParent(MenuComponent*child,vi2d drawPos)override{
|
|
return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawPos);
|
|
}
|
|
virtual inline bool PointWithinParent(MenuComponent*child,geom2d::rect<float> drawRect)override{
|
|
return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawRect);
|
|
}
|
|
virtual inline bool HandleOutsideDisabledButtonSelection(std::weak_ptr<MenuComponent>disabledButton)override{
|
|
//Set the offset so the center is highlighted by this button.
|
|
SetScrollAmount(vf2d{GetScrollAmount().x,GetScrollAmount().y-disabledButton.lock()->rect.pos.y+disabledButton.lock()->rect.size.y});
|
|
return true;
|
|
};
|
|
virtual void Cleanup()override{}
|
|
inline std::vector<std::weak_ptr<MenuComponent>>&GetComponents(){
|
|
return components;
|
|
}
|
|
inline std::vector<std::weak_ptr<MenuComponent>>&GetSubcomponents(){
|
|
return subcomponents;
|
|
}
|
|
virtual inline void Enable()override final{
|
|
MenuComponent::Enable();
|
|
for(std::weak_ptr<MenuComponent>component:components){
|
|
component.lock()->Enable();
|
|
}
|
|
for(std::weak_ptr<MenuComponent>component:subcomponents){
|
|
component.lock()->Enable();
|
|
}
|
|
if(upButton.lock()){upButton.lock()->Enable();}
|
|
if(downButton.lock()){downButton.lock()->Enable();}
|
|
};
|
|
virtual inline void Disable()override final{
|
|
MenuComponent::Disable();
|
|
for(std::weak_ptr<MenuComponent>component:components){
|
|
component.lock()->Disable();
|
|
}
|
|
for(std::weak_ptr<MenuComponent>component:subcomponents){
|
|
component.lock()->Disable();
|
|
}
|
|
if(upButton.lock()){upButton.lock()->Disable();}
|
|
if(downButton.lock()){downButton.lock()->Disable();}
|
|
};
|
|
}; |