diff --git a/Crawler/Menu.cpp b/Crawler/Menu.cpp index 3bb75289..2d37f355 100644 --- a/Crawler/Menu.cpp +++ b/Crawler/Menu.cpp @@ -55,6 +55,7 @@ void Menu::AddComponent(std::string key,MenuComponent*button){ std::cout<<"WARNING! Key "<name=key; components[key]=button; } @@ -92,10 +93,6 @@ void Menu::MenuSelect(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){ HoverMenuSelect(game); } @@ -107,8 +104,14 @@ void Menu::Update(Crawler*game){ } } } + + bool itemHovered=false; + 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{ selection={-1,-1}; for(auto&key:buttons){ @@ -117,6 +120,7 @@ void Menu::Update(Crawler*game){ if(!button->disabled){ if(button->GetHoverState(game)){ button->hovered=true; + itemHovered=true; selection.y=key.first; selection.x=index; } @@ -126,20 +130,40 @@ void Menu::Update(Crawler*game){ } } - if(draggingComponent!=nullptr&&selection!=vi2d{-1,-1}){ - MenuComponent*selectedComponent=buttons[selection.y][selection.x]; + if(itemHovered&&draggingComponent==nullptr&&selection!=vi2d{-1,-1}&&(((!MOUSE_NAVIGATION&&(game->GetKey(ENTER).bHeld)||game->GetKey(SPACE).bHeld))||game->GetMouse(Mouse::LEFT).bHeld)){ + 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(game->GetKey(ENTER).bReleased||game->GetKey(SPACE).bReleased){ + if(selectedComponent==nullptr){//Dropping over an empty area. + ClearDraggingComponent(); + }else if(selectedComponent->DropDraggableItem(draggingComponent)){ - delete draggingComponent; //We know we allocated a new instance of this, so we will now free it. - draggingComponent=nullptr; + ClearDraggingComponent(); } } }else{ if(game->GetMouse(Mouse::LEFT).bReleased){ + if(selectedComponent==nullptr){//Dropping over an empty area. + ClearDraggingComponent(); + }else if(selectedComponent->DropDraggableItem(draggingComponent)){ - delete draggingComponent; //We know we allocated a new instance of this, so we will now free it. - draggingComponent=nullptr; + ClearDraggingComponent(); } } } diff --git a/Crawler/Menu.h b/Crawler/Menu.h index 91431d9d..442c7d85 100644 --- a/Crawler/Menu.h +++ b/Crawler/Menu.h @@ -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 size; //Size in tiles (24x24), every menu will be tile-based + static Theme&GetCurrentTheme(); + private: Menu(vf2d pos,vf2d size); void HoverMenuSelect(Crawler*game); @@ -64,8 +66,6 @@ private: //X (0-3), Y (0-2) for specific 9-patch tile (tiled version). static Renderable&GetPatchPart(int x,int y); - static Theme&GetCurrentTheme(); - void KeyboardButtonNavigation(Crawler*game,vf2d menuPos); void DrawScaledWindowBackground(Crawler*game,vf2d menuPos); void DrawTiledWindowBackground(Crawler*game,vf2d menuPos); diff --git a/Crawler/MenuComponent.cpp b/Crawler/MenuComponent.cpp index 6c6a3044..7d04159f 100644 --- a/Crawler/MenuComponent.cpp +++ b/Crawler/MenuComponent.cpp @@ -5,7 +5,9 @@ MenuComponent::MenuComponent(MenuType parent,geom2d::rectrect,std::string :parentMenu(parent),rect(rect),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(selectable){} MenuComponent::MenuComponent(MenuType parent,geom2d::rectrect,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(){} diff --git a/Crawler/MenuComponent.h b/Crawler/MenuComponent.h index 72c8daed..c5631c33 100644 --- a/Crawler/MenuComponent.h +++ b/Crawler/MenuComponent.h @@ -12,6 +12,7 @@ private: //CALL THIS FOR A PARENT to check a child's DrawDecal validity! virtual bool PointWithinParent(MenuComponent*child,vi2d drawPos); protected: + std::string name=""; geom2d::rectrect; std::string label; bool border=true; diff --git a/Crawler/ScrollableWindowComponent.h b/Crawler/ScrollableWindowComponent.h index dfd0b2f9..b5672310 100644 --- a/Crawler/ScrollableWindowComponent.h +++ b/Crawler/ScrollableWindowComponent.h @@ -12,6 +12,10 @@ protected: MenuComponent*upButton=nullptr; MenuComponent*downButton=nullptr; geom2d::rectbounds; //It's for the scrollbar. + float scrollBarHeight=0; + float scrollBarTop=0; + bool scrollBarSelected=false; + float scrollBarHoverTime=0; private: inline bool OnScreen(MenuComponent*component){ return geom2d::overlaps(rect,geom2d::rect{component->rect.pos+V(A::SCROLL_OFFSET),component->rect.size}); @@ -27,15 +31,43 @@ public: } private: virtual inline void AfterCreate()override{ - upButton=new MenuComponent(parentMenu,{vf2d{rect.size.x-12,0},{12,12}},"^",[](MenuFuncData dat){std::cout<<"Clicked"<AddComponent("scrollableWindowButton"+upButton->rect.pos.str()+"_"+upButton->rect.size.str(),upButton); - Menu::menus[parentMenu]->AddComponent("scrollableWindowButton"+downButton->rect.pos.str()+"_"+downButton->rect.size.str(),downButton); + 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){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;}); + //Let's use the internal name of this component to add unique names for sub-components. + 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: virtual inline void Update(Crawler*game)override{ MenuComponent::Update(game); + vf2d windowAbsPos=Menu::menus[parentMenu]->pos+rect.pos; + + bool mouseOverScrollbar=geom2d::overlaps(geom2d::rect(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){ 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){ component->disabled=!OnScreen(component); 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{ MenuComponent::Draw(game,parentPos,focused); @@ -60,15 +101,28 @@ protected: game->SetDrawTarget(prevDrawTarget); 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{ MenuComponent::DrawDecal(game,parentPos,focused); game->DrawRectDecal(rect.pos+parentPos,rect.size); for(MenuComponent*component:components){ component->_DrawDecal(game,rect.pos+parentPos+V(A::SCROLL_OFFSET),focused); } - game->DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-12,0},{12,12}); - 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}); + DrawScrollbar(game,parentPos,focused); } virtual bool GetHoverState(Crawler*game,MenuComponent*child)override{ return geom2d::overlaps(geom2d::rect{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos+V(A::SCROLL_OFFSET),child->rect.size},game->GetMousePos()); diff --git a/Crawler/Version.h b/Crawler/Version.h index bfb39e87..d151bd25 100644 --- a/Crawler/Version.h +++ b/Crawler/Version.h @@ -2,7 +2,7 @@ #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 0 -#define VERSION_BUILD 2066 +#define VERSION_BUILD 2114 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Crawler/assets/config/gfx/themes.txt b/Crawler/assets/config/gfx/themes.txt index c1f7810a..7a8bcf7d 100644 --- a/Crawler/assets/config/gfx/themes.txt +++ b/Crawler/assets/config/gfx/themes.txt @@ -8,6 +8,8 @@ ThemeGlobal MenuHoldTime = 0.1 # How fast the menu scrolls via Scroll Wheel MenuScrollWheelSpeed = 8 + # How fast the menu scrolls via clicking the Scroll Arrow Buttons + MenuButtonScrollSpeed = 16 } Themes