Added functional scrollbar.
This commit is contained in:
parent
ff3f4ba1c0
commit
daf94db505
@ -55,6 +55,7 @@ void Menu::AddComponent(std::string key,MenuComponent*button){
|
|||||||
std::cout<<"WARNING! Key "<<key<<" for this sub-menu already exists! Key names must be unique!"<<std::endl;
|
std::cout<<"WARNING! Key "<<key<<" for this sub-menu already exists! Key names must be unique!"<<std::endl;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
button->name=key;
|
||||||
components[key]=button;
|
components[key]=button;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,10 +93,6 @@ void Menu::MenuSelect(Crawler*game){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Menu::Update(Crawler*game){
|
void Menu::Update(Crawler*game){
|
||||||
if(draggingComponent==nullptr&&selection!=vi2d{-1,-1}&&(((!MOUSE_NAVIGATION&&(game->GetKey(ENTER).bHeld)||game->GetKey(SPACE).bHeld))||game->GetMouse(Mouse::LEFT).bHeld)){
|
|
||||||
buttonHoldTime+=game->GetElapsedTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(draggingComponent==nullptr){
|
if(draggingComponent==nullptr){
|
||||||
HoverMenuSelect(game);
|
HoverMenuSelect(game);
|
||||||
}
|
}
|
||||||
@ -107,8 +104,14 @@ void Menu::Update(Crawler*game){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool itemHovered=false;
|
||||||
|
|
||||||
if(!MOUSE_NAVIGATION){
|
if(!MOUSE_NAVIGATION){
|
||||||
if(selection!=vi2d{-1,-1})buttons[selection.y][selection.x]->hovered=true;
|
if(selection!=vi2d{-1,-1}){
|
||||||
|
buttons[selection.y][selection.x]->hovered=true;
|
||||||
|
itemHovered=true;
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
selection={-1,-1};
|
selection={-1,-1};
|
||||||
for(auto&key:buttons){
|
for(auto&key:buttons){
|
||||||
@ -117,6 +120,7 @@ void Menu::Update(Crawler*game){
|
|||||||
if(!button->disabled){
|
if(!button->disabled){
|
||||||
if(button->GetHoverState(game)){
|
if(button->GetHoverState(game)){
|
||||||
button->hovered=true;
|
button->hovered=true;
|
||||||
|
itemHovered=true;
|
||||||
selection.y=key.first;
|
selection.y=key.first;
|
||||||
selection.x=index;
|
selection.x=index;
|
||||||
}
|
}
|
||||||
@ -126,20 +130,40 @@ void Menu::Update(Crawler*game){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(draggingComponent!=nullptr&&selection!=vi2d{-1,-1}){
|
if(itemHovered&&draggingComponent==nullptr&&selection!=vi2d{-1,-1}&&(((!MOUSE_NAVIGATION&&(game->GetKey(ENTER).bHeld)||game->GetKey(SPACE).bHeld))||game->GetMouse(Mouse::LEFT).bHeld)){
|
||||||
MenuComponent*selectedComponent=buttons[selection.y][selection.x];
|
buttonHoldTime+=game->GetElapsedTime();
|
||||||
|
}else{
|
||||||
|
buttonHoldTime=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(draggingComponent!=nullptr){
|
||||||
|
MenuComponent*selectedComponent=nullptr;
|
||||||
|
if(selection!=vi2d{-1,-1}){
|
||||||
|
selectedComponent=buttons[selection.y][selection.x];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto ClearDraggingComponent=[&](){
|
||||||
|
delete draggingComponent; //We know we allocated a new instance of this, so we will now free it.
|
||||||
|
draggingComponent=nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
if(!MOUSE_NAVIGATION){
|
if(!MOUSE_NAVIGATION){
|
||||||
if(game->GetKey(ENTER).bReleased||game->GetKey(SPACE).bReleased){
|
if(game->GetKey(ENTER).bReleased||game->GetKey(SPACE).bReleased){
|
||||||
|
if(selectedComponent==nullptr){//Dropping over an empty area.
|
||||||
|
ClearDraggingComponent();
|
||||||
|
}else
|
||||||
if(selectedComponent->DropDraggableItem(draggingComponent)){
|
if(selectedComponent->DropDraggableItem(draggingComponent)){
|
||||||
delete draggingComponent; //We know we allocated a new instance of this, so we will now free it.
|
ClearDraggingComponent();
|
||||||
draggingComponent=nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(game->GetMouse(Mouse::LEFT).bReleased){
|
if(game->GetMouse(Mouse::LEFT).bReleased){
|
||||||
|
if(selectedComponent==nullptr){//Dropping over an empty area.
|
||||||
|
ClearDraggingComponent();
|
||||||
|
}else
|
||||||
if(selectedComponent->DropDraggableItem(draggingComponent)){
|
if(selectedComponent->DropDraggableItem(draggingComponent)){
|
||||||
delete draggingComponent; //We know we allocated a new instance of this, so we will now free it.
|
ClearDraggingComponent();
|
||||||
draggingComponent=nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,8 @@ public:
|
|||||||
vf2d pos; //Specify the upper-left corner of the window. Using CENTERED will always put this where the upper-left corner would center the window.
|
vf2d pos; //Specify the upper-left corner of the window. Using CENTERED will always put this where the upper-left corner would center the window.
|
||||||
vf2d size; //Size in tiles (24x24), every menu will be tile-based
|
vf2d size; //Size in tiles (24x24), every menu will be tile-based
|
||||||
|
|
||||||
|
static Theme&GetCurrentTheme();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Menu(vf2d pos,vf2d size);
|
Menu(vf2d pos,vf2d size);
|
||||||
void HoverMenuSelect(Crawler*game);
|
void HoverMenuSelect(Crawler*game);
|
||||||
@ -64,8 +66,6 @@ private:
|
|||||||
//X (0-3), Y (0-2) for specific 9-patch tile (tiled version).
|
//X (0-3), Y (0-2) for specific 9-patch tile (tiled version).
|
||||||
static Renderable&GetPatchPart(int x,int y);
|
static Renderable&GetPatchPart(int x,int y);
|
||||||
|
|
||||||
static Theme&GetCurrentTheme();
|
|
||||||
|
|
||||||
void KeyboardButtonNavigation(Crawler*game,vf2d menuPos);
|
void KeyboardButtonNavigation(Crawler*game,vf2d menuPos);
|
||||||
void DrawScaledWindowBackground(Crawler*game,vf2d menuPos);
|
void DrawScaledWindowBackground(Crawler*game,vf2d menuPos);
|
||||||
void DrawTiledWindowBackground(Crawler*game,vf2d menuPos);
|
void DrawTiledWindowBackground(Crawler*game,vf2d menuPos);
|
||||||
|
@ -5,7 +5,9 @@ MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string
|
|||||||
:parentMenu(parent),rect(rect),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(selectable){}
|
:parentMenu(parent),rect(rect),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(selectable){}
|
||||||
|
|
||||||
MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,bool selectable)
|
MenuComponent::MenuComponent(MenuType parent,geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,bool selectable)
|
||||||
:parentMenu(parent),rect(rect),label(label),menuDest(menuDest),onClick(onClick),hoverEffect(0),selectable(selectable){}
|
:MenuComponent(parent,rect,label,onClick,selectable){
|
||||||
|
this->menuDest=menuDest;
|
||||||
|
}
|
||||||
|
|
||||||
void MenuComponent::AfterCreate(){}
|
void MenuComponent::AfterCreate(){}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ private:
|
|||||||
//CALL THIS FOR A PARENT to check a child's DrawDecal validity!
|
//CALL THIS FOR A PARENT to check a child's DrawDecal validity!
|
||||||
virtual bool PointWithinParent(MenuComponent*child,vi2d drawPos);
|
virtual bool PointWithinParent(MenuComponent*child,vi2d drawPos);
|
||||||
protected:
|
protected:
|
||||||
|
std::string name="";
|
||||||
geom2d::rect<float>rect;
|
geom2d::rect<float>rect;
|
||||||
std::string label;
|
std::string label;
|
||||||
bool border=true;
|
bool border=true;
|
||||||
|
@ -12,6 +12,10 @@ protected:
|
|||||||
MenuComponent*upButton=nullptr;
|
MenuComponent*upButton=nullptr;
|
||||||
MenuComponent*downButton=nullptr;
|
MenuComponent*downButton=nullptr;
|
||||||
geom2d::rect<float>bounds; //It's for the scrollbar.
|
geom2d::rect<float>bounds; //It's for the scrollbar.
|
||||||
|
float scrollBarHeight=0;
|
||||||
|
float scrollBarTop=0;
|
||||||
|
bool scrollBarSelected=false;
|
||||||
|
float scrollBarHoverTime=0;
|
||||||
private:
|
private:
|
||||||
inline bool OnScreen(MenuComponent*component){
|
inline bool OnScreen(MenuComponent*component){
|
||||||
return geom2d::overlaps(rect,geom2d::rect<float>{component->rect.pos+V(A::SCROLL_OFFSET),component->rect.size});
|
return geom2d::overlaps(rect,geom2d::rect<float>{component->rect.pos+V(A::SCROLL_OFFSET),component->rect.size});
|
||||||
@ -27,15 +31,43 @@ public:
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
virtual inline void AfterCreate()override{
|
virtual inline void AfterCreate()override{
|
||||||
upButton=new MenuComponent(parentMenu,{vf2d{rect.size.x-12,0},{12,12}},"^",[](MenuFuncData dat){std::cout<<"Clicked"<<std::endl;});
|
upButton=new MenuComponent(parentMenu,{vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;});
|
||||||
downButton=new MenuComponent(parentMenu,{rect.size-vf2d{12,12},{12,12}},"v",[](MenuFuncData dat){});
|
downButton=new MenuComponent(parentMenu,{rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;});
|
||||||
Menu::menus[parentMenu]->AddComponent("scrollableWindowButton"+upButton->rect.pos.str()+"_"+upButton->rect.size.str(),upButton);
|
//Let's use the internal name of this component to add unique names for sub-components.
|
||||||
Menu::menus[parentMenu]->AddComponent("scrollableWindowButton"+downButton->rect.pos.str()+"_"+downButton->rect.size.str(),downButton);
|
Menu::menus[parentMenu]->AddComponent(name+upButton->rect.pos.str()+"_"+upButton->rect.size.str(),upButton);
|
||||||
|
Menu::menus[parentMenu]->AddComponent(name+downButton->rect.pos.str()+"_"+downButton->rect.size.str(),downButton);
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
virtual inline void Update(Crawler*game)override{
|
virtual inline void Update(Crawler*game)override{
|
||||||
MenuComponent::Update(game);
|
MenuComponent::Update(game);
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
if(mouseOverScrollbar||scrollBarSelected){
|
||||||
|
scrollBarHoverTime=std::min(scrollBarHoverTime+game->GetElapsedTime(),"ThemeGlobal.HighlightTime"_F);
|
||||||
|
if(game->GetMouse(0).bPressed){
|
||||||
|
scrollBarSelected=true;
|
||||||
|
}
|
||||||
|
if(game->GetMouse(0).bReleased){
|
||||||
|
scrollBarSelected=false;
|
||||||
|
}
|
||||||
|
if(scrollBarSelected){
|
||||||
|
float spaceBetweenTopAndBottomArrows=rect.size.y-24;
|
||||||
|
float viewHeight=rect.size.y;
|
||||||
|
|
||||||
|
|
||||||
|
float totalContentHeight=bounds.size.y;
|
||||||
|
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;
|
||||||
|
V(A::SCROLL_OFFSET).y=(-newScrollbarTop+1)/scrollBarScale;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
scrollBarHoverTime=std::max(scrollBarHoverTime-game->GetElapsedTime(),0.f);
|
||||||
|
}
|
||||||
|
|
||||||
if(game->GetMouseWheel()!=0){
|
if(game->GetMouseWheel()!=0){
|
||||||
if(game->GetMouseWheel()>0){
|
if(game->GetMouseWheel()>0){
|
||||||
V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuScrollWheelSpeed"_I;
|
V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuScrollWheelSpeed"_I;
|
||||||
@ -44,10 +76,19 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
V(A::SCROLL_OFFSET).y=std::clamp(V(A::SCROLL_OFFSET).y,-(bounds.size.y-rect.size.y),0.f);
|
||||||
|
|
||||||
for(MenuComponent*component:components){
|
for(MenuComponent*component:components){
|
||||||
component->disabled=!OnScreen(component);
|
component->disabled=!OnScreen(component);
|
||||||
component->_Update(game);
|
component->_Update(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upButton->disabled=false;
|
||||||
|
downButton->disabled=false;
|
||||||
|
if(geom2d::contains(rect,bounds)){//This means we have no reason to show a scrollbar.
|
||||||
|
upButton->disabled=true;
|
||||||
|
downButton->disabled=true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
virtual inline void Draw(Crawler*game,vf2d parentPos,bool focused)override{
|
virtual inline void Draw(Crawler*game,vf2d parentPos,bool focused)override{
|
||||||
MenuComponent::Draw(game,parentPos,focused);
|
MenuComponent::Draw(game,parentPos,focused);
|
||||||
@ -60,15 +101,28 @@ protected:
|
|||||||
game->SetDrawTarget(prevDrawTarget);
|
game->SetDrawTarget(prevDrawTarget);
|
||||||
game->DrawSprite(parentPos,r.Sprite());
|
game->DrawSprite(parentPos,r.Sprite());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void DrawScrollbar(Crawler*game,vf2d parentPos,bool focused){
|
||||||
|
float spaceBetweenTopAndBottomArrows=rect.size.y-24;
|
||||||
|
float viewHeight=rect.size.y;
|
||||||
|
float totalContentHeight=bounds.size.y;
|
||||||
|
float scrollBarScale=(spaceBetweenTopAndBottomArrows/totalContentHeight);
|
||||||
|
scrollBarHeight=viewHeight*scrollBarScale-1;
|
||||||
|
scrollBarTop=-V(A::SCROLL_OFFSET).y*scrollBarScale+1;
|
||||||
|
|
||||||
|
float focusedWindowColorMult=(focused?1:"ThemeGlobal.MenuUnfocusedColorMult"_F);
|
||||||
|
|
||||||
|
game->FillRectDecal(rect.pos+parentPos+vf2d{rect.size.x-13,scrollBarTop+12},{12,scrollBarHeight},PixelLerp(Menu::GetCurrentTheme().GetButtonCol(),Menu::GetCurrentTheme().GetHighlightCol(),scrollBarHoverTime/"ThemeGlobal.HighlightTime"_F)*focusedWindowColorMult);
|
||||||
|
game->DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-13,scrollBarTop+12},{12,scrollBarHeight},WHITE*focusedWindowColorMult);
|
||||||
|
}
|
||||||
|
|
||||||
virtual inline void DrawDecal(Crawler*game,vf2d parentPos,bool focused)override{
|
virtual inline void DrawDecal(Crawler*game,vf2d parentPos,bool focused)override{
|
||||||
MenuComponent::DrawDecal(game,parentPos,focused);
|
MenuComponent::DrawDecal(game,parentPos,focused);
|
||||||
game->DrawRectDecal(rect.pos+parentPos,rect.size);
|
game->DrawRectDecal(rect.pos+parentPos,rect.size);
|
||||||
for(MenuComponent*component:components){
|
for(MenuComponent*component:components){
|
||||||
component->_DrawDecal(game,rect.pos+parentPos+V(A::SCROLL_OFFSET),focused);
|
component->_DrawDecal(game,rect.pos+parentPos+V(A::SCROLL_OFFSET),focused);
|
||||||
}
|
}
|
||||||
game->DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-12,0},{12,12});
|
DrawScrollbar(game,parentPos,focused);
|
||||||
game->DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-12,12},{12,rect.size.y-24});
|
|
||||||
game->DrawRectDecal(rect.pos+parentPos+rect.size-vf2d{12,12},{12,12});
|
|
||||||
}
|
}
|
||||||
virtual bool GetHoverState(Crawler*game,MenuComponent*child)override{
|
virtual bool GetHoverState(Crawler*game,MenuComponent*child)override{
|
||||||
return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos+V(A::SCROLL_OFFSET),child->rect.size},game->GetMousePos());
|
return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos+V(A::SCROLL_OFFSET),child->rect.size},game->GetMousePos());
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 2
|
#define VERSION_MINOR 2
|
||||||
#define VERSION_PATCH 0
|
#define VERSION_PATCH 0
|
||||||
#define VERSION_BUILD 2066
|
#define VERSION_BUILD 2114
|
||||||
|
|
||||||
#define stringify(a) stringify_(a)
|
#define stringify(a) stringify_(a)
|
||||||
#define stringify_(a) #a
|
#define stringify_(a) #a
|
||||||
|
@ -8,6 +8,8 @@ ThemeGlobal
|
|||||||
MenuHoldTime = 0.1
|
MenuHoldTime = 0.1
|
||||||
# How fast the menu scrolls via Scroll Wheel
|
# How fast the menu scrolls via Scroll Wheel
|
||||||
MenuScrollWheelSpeed = 8
|
MenuScrollWheelSpeed = 8
|
||||||
|
# How fast the menu scrolls via clicking the Scroll Arrow Buttons
|
||||||
|
MenuButtonScrollSpeed = 16
|
||||||
}
|
}
|
||||||
|
|
||||||
Themes
|
Themes
|
||||||
|
Loading…
x
Reference in New Issue
Block a user