Fix border display drawing for menus. Fix scrollable window components that went outside to use proper scrolling offsets. Fix issue with same-frame clicking and releasing causing a different button to be selected.

pull/28/head
sigonasr2 12 months ago
parent 92c093c589
commit 025a89788e
  1. 8
      Crawler/CharacterAbilityPreviewComponent.h
  2. 20
      Crawler/CharacterMenuWindow.cpp
  3. 2
      Crawler/CharacterRotatingDisplay.h
  4. 1
      Crawler/Crawler.cpp
  5. 1
      Crawler/DEFINES.h
  6. 3
      Crawler/InventoryConsumableWindow.cpp
  7. 33
      Crawler/Menu.cpp
  8. 6
      Crawler/MenuAnimatedIconButton.h
  9. 4
      Crawler/MenuAnimatedIconToggleButton.h
  10. 28
      Crawler/MenuComponent.cpp
  11. 4
      Crawler/MenuComponent.h
  12. 6
      Crawler/MenuIconButton.h
  13. 8
      Crawler/MenuItemButton.h
  14. 6
      Crawler/MenuItemItemButton.h
  15. 8
      Crawler/MenuLabel.h
  16. 2
      Crawler/MonsterAttribute.h
  17. 12
      Crawler/PopupMenuLabel.h
  18. 39
      Crawler/ScrollableWindowComponent.h
  19. 6
      Crawler/SpawnEncounterLabel.h
  20. 2
      Crawler/Version.h
  21. 5
      Crawler/olcPixelGameEngine.h
  22. BIN
      x64/Release/Crawler.exe

@ -54,16 +54,16 @@ protected:
virtual void inline Update(Crawler*game)override{
MenuLabel::Update(game);
}
virtual void inline DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
MenuLabel::DrawDecal(window,parentPos,focused);
vi2d iconPos=parentPos+rect.pos+vi2d{5,5};
virtual void inline DrawDecal(ViewPort&window,bool focused)override{
MenuLabel::DrawDecal(window,focused);
vi2d iconPos=rect.pos+vi2d{5,5};
vi2d textPos=iconPos;
float textWidth=game->GetTextSizeProp(ability->input->GetDisplayName()).x*0.5f+4;
float boxWidth=rect.size.y-4; //No, the y is not a typo. It's a square, we use the y to determine the x.
window.DrawRectDecal(parentPos+rect.pos+vi2d{2,2},vi2d{int(rect.size.y)-4,int(rect.size.y)-4});
window.DrawRectDecal(rect.pos+vi2d{2,2},vi2d{int(rect.size.y)-4,int(rect.size.y)-4});
window.DrawDecal(iconPos,GFX[ability->icon].Decal());
vi2d descriptionPos=iconPos+vi2d{int(rect.size.y)-2,-1};

@ -53,10 +53,10 @@ INCLUDE_GFX
void Menu::InitializeCharacterMenuWindow(){
static bool equipmentWindowOpened=false;
vf2d windowSize=game->GetScreenSize()-vf2d{52,0};
vf2d windowSize=game->GetScreenSize()-vf2d{52,52};
Menu*characterMenuWindow=CreateMenu(CHARACTER_MENU,CENTERED,windowSize);
characterMenuWindow->ADD("Character Label",MenuLabel)({{0,2},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
characterMenuWindow->ADD("Character Label",MenuLabel)({{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
characterMenuWindow->ADD("Equip Slot Outline",MenuComponent)({{0,28},{120,windowSize.y-48}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
characterMenuWindow->ADD("Character Rotating Display",CharacterRotatingDisplay)({{135,28},{90,windowSize.y-48}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal())END;
@ -71,13 +71,13 @@ void Menu::InitializeCharacterMenuWindow(){
};
characterMenuWindow->ADD("Equip Selection Outline",MenuComponent)({{123,28},{120,windowSize.y-48}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
characterMenuWindow->ADD("Equip Selection Outline",MenuComponent)({{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
->Enable(false);
characterMenuWindow->ADD("Equip List",ScrollableWindowComponent)({{123,28},{120,windowSize.y-48-24}})DEPTH -1 END
characterMenuWindow->ADD("Equip List",ScrollableWindowComponent)({{123,28},{120,windowSize.y-37-24}})DEPTH -1 END
->Enable(false);
characterMenuWindow->ADD("Equip Selection Bottom Outline",MenuComponent)({{123,28+(windowSize.y-48-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
characterMenuWindow->ADD("Equip Selection Bottom Outline",MenuComponent)({{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
->Enable(false);
auto equipSelectionSelectButton=characterMenuWindow->ADD("Equip Selection Select Button",MenuComponent)({{123+12,28+(windowSize.y-48-24)+6},{96,12}},"Select",
auto equipSelectionSelectButton=characterMenuWindow->ADD("Equip Selection Select Button",MenuComponent)({{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select",
[](MenuFuncData data){
Component<MenuComponent>(data.component->parentMenu,"Equip Selection Outline")->Enable(false);
Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List")->Enable(false);
@ -218,7 +218,7 @@ void Menu::InitializeCharacterMenuWindow(){
Menu::AddEquipStatListener(equipmentSlot);
}
characterMenuWindow->ADD("Stat Display Outline",MenuComponent)({{245,28},{62,windowSize.y-48}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
characterMenuWindow->ADD("Stat Display Outline",MenuComponent)({{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
int yOffset=0;
for(ItemAttribute attribute:displayAttrs){
@ -229,12 +229,12 @@ void Menu::InitializeCharacterMenuWindow(){
yOffset+=20;
}
characterMenuWindow->ADD("Back button",MenuComponent)({{windowSize.x/2-64,windowSize.y-16},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;})END;
characterMenuWindow->ADD("Back button",MenuComponent)({{windowSize.x/2-64,windowSize.y},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;})END;
auto itemNameDisplay=characterMenuWindow->ADD("Item Name",MenuLabel)({{0,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
auto itemDescriptionDisplay=characterMenuWindow->ADD("Item Description",MenuLabel)({{0,40},{120,windowSize.y-60}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
auto itemDescriptionDisplay=characterMenuWindow->ADD("Item Description",MenuLabel)({{0,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
auto itemEquipNameDisplay=characterMenuWindow->ADD("Item Equip Name",MenuLabel)({{123,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
auto itemEquipDescriptionDisplay=characterMenuWindow->ADD("Item Equip Description",MenuLabel)({{123,40},{120,windowSize.y-60}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
auto itemEquipDescriptionDisplay=characterMenuWindow->ADD("Item Equip Description",MenuLabel)({{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
itemNameDisplay->Enable(false);
itemDescriptionDisplay->Enable(false);

@ -62,7 +62,7 @@ protected:
timer-=2*PI;
}
}
virtual inline void DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
window.DrawWarpedDecal(icon,std::array<vf2d,4>{
rect.pos+vf2d{abs(sin(timer)),sin(float(timer+PI))}*vf2d{rotatingFactor,perspectiveFactor},
rect.pos+vf2d{0,rect.size.y}+vf2d{abs(sin(timer)),sin(timer)}*vf2d{rotatingFactor,perspectiveFactor},

@ -215,7 +215,6 @@ bool Crawler::OnUserCreate(){
}
bool Crawler::OnUserUpdate(float fElapsedTime){
fElapsedTime=std::clamp(fElapsedTime,0.f,1/30.f); //HACK fix. We can't have a negative time. Although using a more precise system clock should make this never occur. Also make sure if the game is too slow we advance by only 1/30th of a second.
levelTime+=fElapsedTime;
if(!GamePaused()){
GameState::STATE->OnUserUpdate(this);

@ -54,6 +54,7 @@ All rights reserved.
#define INCLUDE_ITEM_CATEGORIES extern safemap<std::string,std::set<std::string>>ITEM_CATEGORIES;
#define DO_NOTHING [](MenuFuncData data){return true;}
#define INCLUDE_LEVEL_NAMES extern safemap<std::string,MapName>LEVEL_NAMES;
#define INCLUDE_WINDOW_SIZE extern vi2d WINDOW_SIZE;
#define INCLUDE_CENTERED extern const vf2d Menu::CENTERED;

@ -61,7 +61,8 @@ void Menu::InitializeConsumableInventoryWindow(){
data.game->ClearLoadoutItem(data.menu.I(A::LOADOUT_SLOT));
for(MenuComponent*component:data.parentComponent->GetComponents()){ //HACK ALERT! If we are accessing a parent component, it's because we are dealing with a scrolling window component, which has sub-components. So this should be a safe cast to make.
if(component->GetName().starts_with("item")){
MenuItemButton*button2=(MenuItemButton*)component;//HACK ALERT! This is probably an item since we populated item lists using this name for the components. So we assume these are MenuItemButton classes.
MenuItemButton*button2=dynamic_cast<MenuItemButton*>(component);//HACK ALERT! This is probably an item since we populated item lists using this name for the components. So we assume these are MenuItemButton classes.
if(button2==nullptr)continue;
if(button2==button){
if(button2->selected!=-1){
data.game->ClearLoadoutItem(button2->selected);

@ -69,13 +69,13 @@ std::string Menu::lastRegisteredComponent;
INCLUDE_game
INCLUDE_GFX
extern vi2d WINDOW_SIZE;
INCLUDE_WINDOW_SIZE
using A=Attribute;
Menu::Menu(vf2d pos,vf2d size)
:pos(pos==CENTERED?WINDOW_SIZE/2-size/2:vi2d{pos}),size(size){
this->window=ViewPort::rectViewPort({0,0},size,this->pos);
this->window=ViewPort::rectViewPort({-24,-24},this->size+vi2d{48,48},this->pos);
}
Menu::~Menu(){
@ -202,11 +202,14 @@ void Menu::Update(Crawler*game){
itemHovered=true;
selection.y=key;
selection.x=index;
goto selected;
}
}
index++;
}
}
selected:
int a;
}
if(itemHovered&&draggingComponent==nullptr&&selection!=vi2d{-1,-1}&&(((!UsingMouseNavigation()&&(game->GetKey(ENTER).bHeld)||game->GetKey(SPACE).bHeld))||game->GetMouse(Mouse::LEFT).bHeld)){
@ -305,11 +308,16 @@ void Menu::Draw(Crawler*game){
MenuComponent*selectedComponent=buttons[selection.y][selection.x];
vf2d drawOffset{};
if(selectedComponent->parentComponent!=nullptr){
drawOffset+=selectedComponent->parentComponent->V(A::SCROLL_OFFSET);
ScrollableWindowComponent*scrollableComponent=dynamic_cast<ScrollableWindowComponent*>(selectedComponent->parentComponent);
if(scrollableComponent!=nullptr){
drawOffset+=scrollableComponent->GetScrollAmount();
}
draggingComponent->DrawDecal(window,drawOffset+pos-offsetPos+selectedComponent->rect.pos+vi2d{1,-4},this==Menu::stack.back());
}
draggingComponent->V(A::DRAW_OFFSET)=drawOffset+pos-offsetPos+selectedComponent->rect.pos+vi2d{1,-4};
draggingComponent->DrawDecal(window,this==Menu::stack.back());
}else{
draggingComponent->DrawDecal(window,-offsetPos+game->GetMousePos(),this==Menu::stack.back());
draggingComponent->V(A::DRAW_OFFSET)-offsetPos+game->GetMousePos();
draggingComponent->DrawDecal(window,this==Menu::stack.back());
}
}
};
@ -435,20 +443,7 @@ void Menu::KeyboardButtonNavigation(Crawler*game,vf2d menuPos){
selection={0,firstInd};
}
}
}else{//Mouse click.
selection={-1,-1};
for(auto&[key,value]:buttons){
int index=0;
for(auto&button:value){
if(!button->disabled){
if(geom2d::overlaps(geom2d::rect<float>{button->rect.pos+menuPos,button->rect.size},game->GetMousePos())){
selection={index,key};
break;
}
}
index++;
}
}
}else{
buttonHoldTime=0;
}
}

@ -55,10 +55,10 @@ protected:
MenuIconButton::Update(game);
animationTime+=game->GetElapsedTime();
}
virtual inline void DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
MenuComponent::DrawDecal(window,parentPos,focused); //INTENTIONAL! The way we draw animations is different from static images, we skip over MenuIconButton's draw!
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
MenuComponent::DrawDecal(window,focused); //Skipping to MenuComponent's DrawDecal is INTENTIONAL! The way we draw animations is different from static images, we skip over MenuIconButton's draw!
Decal*spr=ANIMATION_DATA[animation].GetFrame(animationTime).GetSourceImage()->Decal();
geom2d::rect<int>sprRect=ANIMATION_DATA[animation].GetFrame(animationTime).GetSourceRect();
window.DrawPartialDecal(parentPos+rect.middle()-sprRect.size/2,spr,sprRect.pos,sprRect.size);
window.DrawPartialDecal(rect.middle()-sprRect.size/2,spr,sprRect.pos,sprRect.size);
}
};

@ -63,8 +63,8 @@ protected:
hoverEffect="ThemeGlobal.HighlightTime"_F; //A hack that allows us to make it look like we have this selected.
}
}
virtual inline void DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
MenuAnimatedIconButton::DrawDecal(window,parentPos,focused);
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
MenuAnimatedIconButton::DrawDecal(window,focused);
if(IsSelected()){
window.DrawRectDecal(rect.pos+vi2d{2,2},rect.size-vi2d{4,4},YELLOW);
}

@ -45,7 +45,7 @@ INCLUDE_game
using A=Attribute;
MenuComponent::MenuComponent(geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes)
:rect(rect),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()){
:rect(rect),originalPos(rect.pos),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()){
Menu::unhandledComponents.push_back(this);
}
@ -95,26 +95,26 @@ void MenuComponent::_Update(Crawler*game){
void MenuComponent::OnEquipStatsUpdate(){}
void MenuComponent::DrawDecal(ViewPort&window,vf2d parentPos,bool focused){
void MenuComponent::DrawDecal(ViewPort&window,bool focused){
if(background){
window.FillRectDecal(rect.pos+parentPos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F));
window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET),rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F));
}
if(selected&&selectionType==HIGHLIGHT){
window.FillRectDecal(rect.pos+parentPos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),util::lerp(0.75f,1.0f,hoverEffect/"ThemeGlobal.HighlightTime"_F)));
window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET),rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),util::lerp(0.75f,1.0f,hoverEffect/"ThemeGlobal.HighlightTime"_F)));
}
if(border){
window.FillRectDecal(rect.pos+parentPos,{rect.size.x+1,1});
window.FillRectDecal(rect.pos+parentPos,{1,rect.size.y+1});
window.FillRectDecal(rect.pos+parentPos+vf2d{rect.size.x-1+1,0},{1,rect.size.y+1});
window.FillRectDecal(rect.pos+parentPos+vf2d{0,rect.size.y-1+1},{rect.size.x+1,1});
window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET),{rect.size.x+1,1});
window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET),{1,rect.size.y+1});
window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET)+vf2d{rect.size.x-1+1,0},{1,rect.size.y+1});
window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET)+vf2d{0,rect.size.y-1+1},{rect.size.x+1,1});
}
if(showDefaultLabel){
window.DrawStringPropDecal(rect.pos+parentPos+rect.size/2-vf2d(game->GetTextSizeProp(label))/2.f*labelScaling,label,WHITE,labelScaling);
window.DrawStringPropDecal(rect.pos+V(A::DRAW_OFFSET)+rect.size/2-vf2d(game->GetTextSizeProp(label))/2.f*labelScaling,label,WHITE,labelScaling);
}
if(selected){
switch(selectionType){
case CROSSHAIR:drawutil::DrawCrosshairDecalViewPort(window,{parentPos+rect.pos,rect.size},0);break;
case INNER_BOX:window.DrawRectDecal(rect.pos+parentPos+vi2d{1,1},rect.size-vi2d{2,2});break;
case CROSSHAIR:drawutil::DrawCrosshairDecalViewPort(window,{rect.pos+V(A::DRAW_OFFSET),rect.size},0);break;
case INNER_BOX:window.DrawRectDecal(rect.pos+V(A::DRAW_OFFSET)+vi2d{1,1},rect.size-vi2d{2,2});break;
case HIGHLIGHT:break;//Not used.
default:ERR("Undefined selection type selected: "<<int(selectionType));
}
@ -122,12 +122,8 @@ void MenuComponent::DrawDecal(ViewPort&window,vf2d parentPos,bool focused){
}
void MenuComponent::_DrawDecal(ViewPort&window,bool focused){
_DrawDecal(window,{0,0},focused);
}
void MenuComponent::_DrawDecal(ViewPort&window,vf2d parentPos,bool focused){
if(!disabled){
DrawDecal(window,parentPos,focused);
DrawDecal(window,focused);
}
}

@ -74,7 +74,6 @@ private:
virtual void BeforeUpdate(Crawler*game);
void _Update(Crawler*game);
void _DrawDecal(ViewPort&window,bool focused);
void _DrawDecal(ViewPort&window,vf2d parentPos,bool focused);
bool selected=false;
SelectionType selectionType=CROSSHAIR;
protected:
@ -82,6 +81,7 @@ protected:
float hoverEffect=0;
std::string name="";
geom2d::rect<float>rect;
vf2d originalPos;
std::string label;
bool border=true;
bool draggable=false;
@ -96,7 +96,7 @@ protected:
bool valid=true; //If set to false, this would cause the component to be removed.
vf2d labelScaling={1,1};
virtual void Update(Crawler*game);
virtual void DrawDecal(ViewPort&window,vf2d parentPos,bool focused);
virtual void DrawDecal(ViewPort&window,bool focused);
virtual bool GetHoverState(Crawler*game,MenuComponent*child);
virtual void AfterCreate(); //Called after the creation of all menus finish.
//CALL THIS FOR A PARENT to check a child's DrawDecal validity!

@ -59,11 +59,11 @@ protected:
virtual inline void Update(Crawler*game)override{
MenuComponent::Update(game);
}
virtual inline void DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
MenuComponent::DrawDecal(window,parentPos,focused);
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
MenuComponent::DrawDecal(window,focused);
if(icon!=nullptr){
vf2d iconScale=rect.size/24.f;
window.DrawDecal(parentPos+rect.middle()-icon->sprite->Size()*iconScale/2,icon,iconScale);
window.DrawDecal(rect.middle()-icon->sprite->Size()*iconScale/2,icon,iconScale);
}
}
};

@ -133,10 +133,10 @@ protected:
}
}
}
virtual inline void DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
MenuIconButton::DrawDecal(window,parentPos,focused);
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
MenuIconButton::DrawDecal(window,focused);
if(selected!=-1){
drawutil::DrawCrosshairDecalViewPort(window,{parentPos+rect.pos,rect.size},0);
drawutil::DrawCrosshairDecalViewPort(window,{rect.pos,rect.size},0);
}
if(valid){
int itemQuantity=Inventory::GetItemCount(invRef.at(inventoryIndex).Name()); //Normally we'd retrieve how many of this item we have from our inventory...However Monster Loot and Stage Loot inventories are special and hold their own inventory counts...
@ -146,7 +146,7 @@ protected:
std::string quantityText="x"+std::to_string(itemQuantity);
vf2d quantityTextScale=rect.size/48.f;
vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale;
vf2d drawPos=parentPos+rect.pos+rect.size-textSize;
vf2d drawPos=rect.pos+rect.size-textSize;
geom2d::rect<float>boundingBox={drawPos,textSize};
window.DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale,quantityTextScale.x);
}

@ -131,13 +131,13 @@ protected:
}
}
}
virtual inline void DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
MenuIconButton::DrawDecal(window,parentPos,focused);
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
MenuIconButton::DrawDecal(window,focused);
if(valid&&!hideQty){
std::string quantityText="x"+std::to_string(itemRef.get().Amt());
vf2d quantityTextScale=rect.size/48.f;
vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale;
vf2d drawPos=parentPos+rect.pos+rect.size-textSize;
vf2d drawPos=rect.pos+rect.size-textSize;
geom2d::rect<float>boundingBox={drawPos,textSize};
window.DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale,quantityTextScale.x);
}

@ -64,12 +64,12 @@ protected:
virtual void inline Update(Crawler*game)override{
MenuComponent::Update(game);
}
virtual void inline DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
MenuComponent::DrawDecal(window,parentPos,focused);
virtual void inline DrawDecal(ViewPort&window,bool focused)override{
MenuComponent::DrawDecal(window,focused);
std::string wrappedText=util::WrapText(game,label,int(rect.size.x),true,{float(scale),float(scale)});
vf2d drawPos=parentPos+rect.middle()-vf2d{game->GetTextSizeProp(wrappedText)}*float(scale)/2; //Assume centered.
vf2d drawPos=rect.middle()-vf2d{game->GetTextSizeProp(wrappedText)}*float(scale)/2; //Assume centered.
if(!centered){
drawPos=vf2d{rect.pos.x+2,rect.middle().y-game->GetTextSizeProp(wrappedText).y/2}+parentPos; //We should at least vertically align here.
drawPos=vf2d{rect.pos.x+2,rect.middle().y-game->GetTextSizeProp(wrappedText).y/2}; //We should at least vertically align here.
}
if(shadow){
window.DrawShadowStringPropDecal(drawPos,wrappedText,WHITE,BLACK,{float(scale),float(scale)});

@ -65,11 +65,11 @@ enum class Attribute{
JUMP_TOWARDS_PLAYER,
HITS_UNTIL_DEATH, //When this is set, it is reduced by 1 each time the monster is hit.
INDEXED_THEME,
SCROLL_OFFSET,
CLASS_SELECTION, //A class name that represents what the menu's class is.
LOADOUT_SLOT, //Which loadout slot we are selecting an item for.
ALLOW_DRAGGING, //Whether or not to allow inventory dragging.
EQUIP_TYPE,
BASE_TEXT,
CATEGORY_NAME,
DRAW_OFFSET,
};

@ -57,21 +57,21 @@ protected:
virtual void inline Update(Crawler*game)override{
MenuLabel::Update(game);
}
virtual void inline DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
virtual void inline DrawDecal(ViewPort&window,bool focused)override{
if(label.length()>0){
std::string wrappedText=util::WrapText(game,label,int(rect.size.x-1),true,scale);
vf2d drawPos=parentPos+rect.middle()-vf2d{game->GetTextSizeProp(wrappedText)}*scale/2; //Assume centered.
vf2d drawPos=rect.middle()-vf2d{game->GetTextSizeProp(wrappedText)}*scale/2; //Assume centered.
if(!centered){
drawPos=vf2d{rect.pos.x+2,rect.middle().y-game->GetTextSizeProp(wrappedText).y/2}+parentPos; //We should at least vertically align here.
drawPos=vf2d{rect.pos.x+2,rect.middle().y-game->GetTextSizeProp(wrappedText).y/2}; //We should at least vertically align here.
}
if(background){
window.FillRectDecal(rect.pos+parentPos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F));
window.FillRectDecal(rect.pos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F));
}
if(border){
window.DrawRectDecal(rect.pos+parentPos,rect.size);
window.DrawRectDecal(rect.pos,rect.size);
}
if(showDefaultLabel){
window.DrawStringPropDecal(rect.pos+parentPos+rect.size/2-game->GetTextSizeProp(label)/2,label);
window.DrawStringPropDecal(rect.pos+rect.size/2-game->GetTextSizeProp(label)/2,label);
}
if(shadow){
window.DrawShadowStringPropDecal(drawPos,wrappedText,WHITE,BLACK,scale);

@ -54,9 +54,10 @@ protected:
float scrollBarTop=0;
bool scrollBarSelected=false;
float scrollBarHoverTime=0;
vf2d scrollOffset;
protected:
inline bool OnScreen(MenuComponent*component){
return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component->rect.pos+V(A::SCROLL_OFFSET)+vf2d{2,2},component->rect.size-vf2d{2,2}});
return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component->rect.pos+vf2d{2,2},component->rect.size-vf2d{2,2}});
}
public:
inline ScrollableWindowComponent(geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
@ -93,11 +94,20 @@ public:
Menu::menus[button->parentMenu]->RecalculateComponentCount();
delete button;
}
virtual inline void SetScrollAmount(vf2d scrollOffset){
this->scrollOffset=scrollOffset;
for(MenuComponent*component:components){
component->rect.pos=component->originalPos+scrollOffset;
}
}
virtual inline vf2d GetScrollAmount(){
return scrollOffset;
}
protected:
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)({rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH -1 END;
downButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+rect.size-vf2d{12,12}).str()+"_"+vf2d(12,12).str(),MenuComponent)({rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH -1 END;
upButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+vf2d{rect.size.x-12,0}).str()+"_"+vf2d(12,12).str(),MenuComponent)({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 -1 END;
downButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+rect.size-vf2d{12,12}).str()+"_"+vf2d(12,12).str(),MenuComponent)({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 -1 END;
subWindow=ViewPort::rectViewPort({},rect.size,Menu::menus[parentMenu]->pos+rect.pos);
if(upButton){upButton->Enable(!disabled);}
if(downButton){downButton->Enable(!disabled);}
@ -132,7 +142,7 @@ protected:
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; //Derived formula from the draw code.
SetScrollAmount({GetScrollAmount().x,(-newScrollbarTop+1)/scrollBarScale});
}
}else{
scrollBarHoverTime=std::max(scrollBarHoverTime-game->GetElapsedTime(),0.f);
@ -140,16 +150,16 @@ protected:
if(game->GetMouseWheel()!=0){
if(game->GetMouseWheel()>0){
V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuScrollWheelSpeed"_I;
SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
}else{
V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuScrollWheelSpeed"_I;
SetScrollAmount(GetScrollAmount()-vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
}
}
if(bounds.size.y-rect.size.y>0){
V(A::SCROLL_OFFSET).y=std::clamp(V(A::SCROLL_OFFSET).y,-(bounds.size.y-rect.size.y),0.f);
SetScrollAmount({GetScrollAmount().x,std::clamp(GetScrollAmount().y,-(bounds.size.y-rect.size.y),0.f)});
}else{
V(A::SCROLL_OFFSET).y=0;
SetScrollAmount({GetScrollAmount().x,0});
}
std::sort(components.begin(),components.end(),[](MenuComponent*c1,MenuComponent*c2){return c1->depth>c2->depth;});
@ -172,7 +182,7 @@ protected:
if(totalContentHeight==0)totalContentHeight=1;
float scrollBarScale=(spaceBetweenTopAndBottomArrows/totalContentHeight);
scrollBarHeight=std::min(spaceBetweenTopAndBottomArrows,viewHeight*scrollBarScale-1);
scrollBarTop=-V(A::SCROLL_OFFSET).y*scrollBarScale+1;
scrollBarTop=-GetScrollAmount().y*scrollBarScale+1;
float focusedWindowColorMult=(focused?1:"ThemeGlobal.MenuUnfocusedColorMult"_F);
@ -180,18 +190,18 @@ protected:
window.DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-11.75f,scrollBarTop+12},{12,scrollBarHeight},WHITE*focusedWindowColorMult);
}
virtual inline void DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
MenuComponent::DrawDecal(window,parentPos,focused);
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
MenuComponent::DrawDecal(window,focused);
if(border){
window.DrawRectDecal(rect.pos,rect.size);
}
for(MenuComponent*component:components){
component->_DrawDecal(subWindow,V(A::SCROLL_OFFSET),focused);
component->_DrawDecal(subWindow,focused);
}
DrawScrollbar(window,{},focused);
}
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,child->rect.size},game->GetMousePos());
}
//Calculates the bounds of all components.
geom2d::rect<float> inline CalculateBounds(){
@ -255,8 +265,7 @@ public:
}
virtual inline bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton)override{
//Set the offset so the center is highlighted by this button.
V(A::SCROLL_OFFSET).y=-(disabledButton->rect.pos.y-disabledButton->rect.size.y/2);
V(A::SCROLL_OFFSET).y+=rect.size.y/2;
SetScrollAmount(vf2d{GetScrollAmount().x,-disabledButton->rect.pos.y+disabledButton->rect.size.y});
return true;
};
virtual void Cleanup()override{}

@ -64,16 +64,16 @@ protected:
MenuComponent::Update(game);
anim.UpdateState(state,game->GetElapsedTime());
}
virtual void inline DrawDecal(ViewPort&window,vf2d parentPos,bool focused)override{
virtual void inline DrawDecal(ViewPort&window,bool focused)override{
const geom2d::rect<int>&imgRect=anim.GetFrame(state).GetSourceRect();
vf2d imgSize=vf2d{rect.size.y,rect.size.y};
vf2d imgScale=imgSize/vf2d{imgRect.size};
window.DrawPartialDecal(parentPos+rect.pos,imgSize,anim.GetFrame(state).GetSourceImage()->Decal(),imgRect.pos,imgRect.size);
window.DrawPartialDecal(rect.pos,imgSize,anim.GetFrame(state).GetSourceImage()->Decal(),imgRect.pos,imgRect.size);
float verticalAlignYOffset=(rect.size.y-8)/2;
std::string monsterName=MONSTER_DATA.at(monsterID).GetDisplayName();
vf2d monsterNameTextSize=game->GetTextSizeProp(monsterName);
float textXSpaceAvailable=rect.size.x-imgSize.x-4-16/*12 for the scrollbar*/;
float textXScaling=textXSpaceAvailable/monsterNameTextSize.x;
window.DrawShadowStringPropDecal(parentPos+rect.pos+vf2d{imgSize.x+4,verticalAlignYOffset},monsterName,WHITE,BLACK,{std::min(1.f,textXScaling),1});
window.DrawShadowStringPropDecal(rect.pos+vf2d{imgSize.x+4,verticalAlignYOffset},monsterName,WHITE,BLACK,{std::min(1.f,textXScaling),1});
}
};

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0
#define VERSION_MINOR 2
#define VERSION_PATCH 1
#define VERSION_BUILD 3941
#define VERSION_BUILD 3969
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -4328,7 +4328,8 @@ namespace olc
m_tp1 = m_tp2;
// Our time per frame coefficient
float fElapsedTime = elapsedTime.count();
float actualElapsedTime = elapsedTime.count();
float fElapsedTime = std::clamp(elapsedTime.count(),0.f,1/30.f); //HACK fix. We can't have a negative time. Although using a more precise system clock should make this never occur. Also make sure if the game is too slow we advance by only 1/30th of a second.
fLastElapsed = fElapsedTime;
fRunTime += fElapsedTime;
@ -4441,7 +4442,7 @@ namespace olc
renderer->DisplayFrame();
// Update Title Bar
fFrameTimer += fElapsedTime;
fFrameTimer += actualElapsedTime;
nFrameCount++;
if (fFrameTimer >= 1.0f)
{

Binary file not shown.
Loading…
Cancel
Save