From 03cd07f6b8c4e65609bc7975c45b517cf243e8a4 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Wed, 30 Aug 2023 18:05:51 -0500 Subject: [PATCH] Textbox hovering controlling fixed. --- olcCodeJam2023Entry/Textbox.cpp | 82 +++++++++++++ olcCodeJam2023Entry/Textbox.h | 32 +++++ olcCodeJam2023Entry/Unit.cpp | 6 +- olcCodeJam2023Entry/VirusAttack.cpp | 109 +++++++----------- olcCodeJam2023Entry/VirusAttack.h | 3 + .../olcCodeJam2023Entry.vcxproj | 2 + .../olcCodeJam2023Entry.vcxproj.filters | 6 + olcCodeJam2023Entry/olcPGEX_QuickGUI.h | 15 ++- 8 files changed, 185 insertions(+), 70 deletions(-) create mode 100644 olcCodeJam2023Entry/Textbox.cpp create mode 100644 olcCodeJam2023Entry/Textbox.h diff --git a/olcCodeJam2023Entry/Textbox.cpp b/olcCodeJam2023Entry/Textbox.cpp new file mode 100644 index 0000000..390158c --- /dev/null +++ b/olcCodeJam2023Entry/Textbox.cpp @@ -0,0 +1,82 @@ +#include "Textbox.h" +#include "olcUTIL_Geometry2D.h" + +Textbox::Textbox(){}; + +void Textbox::Initialize(std::string text,vf2d pos,std::string headerText,vf2d maxSize,std::vectorresourceCost,float letterDisplayDelay) +{ + if(GetCurrentString()!=text){ //Make sure this is actually a new textbox + SetDefaults(); + this->text=text; + this->headerText=headerText; + this->maxSize=maxSize; + this->resourceCost=resourceCost; + this->letterDisplayDelay=letterDisplayDelay; + visible=true; + } +} + +void Textbox::SetDefaults(){ + lastLetterTime=0; + textboxMarker=-1; + lastWordMarker=-1; + lastWord=""; + displayText=""; + text=""; +} + +void Textbox::Update(PixelGameEngine*pge){ + lastLetterTime-=pge->GetElapsedTime(); + if(lastLetterTime<=0){ + if(textboxMarkerGetTextSizeProp(tempText).x>=maxSize.x){ + displayText=displayText.substr(0,lastWordMarker); + displayText+='\n'; + displayText+=lastWord; + } + if(text[textboxMarker+1]==' '||text[textboxMarker+1]=='\n'){ + lastWord=""; + lastWordMarker=textboxMarker+2; + } else { + lastWord+=text[textboxMarker+1]; + } + displayText+=text[textboxMarker+1]; + textboxMarker++; + } + lastLetterTime=letterDisplayDelay; + } +} + + +void Textbox::Draw(PixelGameEngine*pge,Resources&resources){ + if(visible){ + vf2d finalPos=pos; + geom2d::rectboxRect={pos-vf2d{2,2},maxSize+vf2d{4,4}}; + pge->FillRectDecal(pos-vf2d{2,2},maxSize+vf2d{4,4},VERY_DARK_GREEN); + pge->DrawRectDecal(pos-vf2d{1,1},maxSize+vf2d{3,3},WHITE); + pge->DrawShadowStringPropDecal(pos+vf2d{1,1},displayText,{220,220,220}); + } +} + +void Textbox::UpdatePosition(vf2d newPos){ + pos=newPos; +} + +std::string&Textbox::GetCurrentString(){ + return text; +} + +void Textbox::SetVisible(bool visible){ + this->visible=visible; + if(!visible){ + SetDefaults(); + } +} + +void Textbox::UpdateAndDraw(vf2d pos,PixelGameEngine*pge,Resources&resources){ + UpdatePosition(pos); + Update(pge); + Draw(pge,resources); +} \ No newline at end of file diff --git a/olcCodeJam2023Entry/Textbox.h b/olcCodeJam2023Entry/Textbox.h new file mode 100644 index 0000000..9e95cf3 --- /dev/null +++ b/olcCodeJam2023Entry/Textbox.h @@ -0,0 +1,32 @@ +#pragma once +#include "olcPixelGameEngine.h" +#include "Unit.h" +#include "olcPGEX_TransformedView.h" +#include "Resources.h" + +class Textbox{ + std::string headerText=""; //If a textbox has a header, it displays at the top in a special color. + std::string text=""; + std::string displayText=""; + vf2d pos={}; + vf2d maxSize={}; + float lastLetterTime=0; + float letterDisplayDelay=0.01; + int textboxMarker=-1; + int lastWordMarker=-1; + std::string lastWord=""; + std::vector resourceCost; //If resource cost is greater than 0, shows them. + bool visible=true; +public: + Textbox(); + void Initialize(std::string text,vf2d pos,std::string headerText="",vf2d maxSize={120,64},std::vectorresourceCost={},float letterDisplayDelay=0.01); + + void UpdateAndDraw(vf2d pos,PixelGameEngine*pge,Resources&resources); + std::string&GetCurrentString(); + void SetVisible(bool visible); +private: + void Update(PixelGameEngine*pge); + void UpdatePosition(vf2d newPos); + void Draw(PixelGameEngine*pge,Resources&resources); + void SetDefaults(); +}; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Unit.cpp b/olcCodeJam2023Entry/Unit.cpp index 4d583db..1455130 100644 --- a/olcCodeJam2023Entry/Unit.cpp +++ b/olcCodeJam2023Entry/Unit.cpp @@ -27,7 +27,7 @@ void BasicUnit2::Attack(Unit&victim,std::vector>&otherUnit } std::string LeftShifter::unitName="Left Shifter"; -std::string LeftShifter::unitDescription="Memory Shifts target memory 1 bit to the left"; +std::string LeftShifter::unitDescription="Memory Shifts target memory 1 bit to the left."; std::vector LeftShifter::resourceCost={{RANGE,2},{ATKSPD,2},{MOVESPD,3},{PROCEDURE,1},{HEALTH,4}}; LeftShifter::LeftShifter(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit(pge,LeftShifter::resourceCost,pos,12,*IMAGES[LEFT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} @@ -37,7 +37,7 @@ void LeftShifter::Attack(Unit&victim,std::vector>&otherUni } std::string RightShifter::unitName="Right Shifter"; -std::string RightShifter::unitDescription="Memory Shifts target memory 1 bit to the right"; +std::string RightShifter::unitDescription="Memory Shifts target memory 1 bit to the right."; std::vector RightShifter::resourceCost={{HEALTH,4},{RANGE,2},{ATKSPD,2},{MOVESPD,3},{PROCEDURE,1}}; RightShifter::RightShifter(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit(pge,RightShifter::resourceCost,pos,12,*IMAGES[RIGHT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} @@ -47,7 +47,7 @@ void RightShifter::Attack(Unit&victim,std::vector>&otherUn } std::string BitRestorer::unitName="Bit Restorer"; -std::string BitRestorer::unitDescription="Randomly restores 1 missing bit to a target"; +std::string BitRestorer::unitDescription="Randomly restores 1 missing bit to a target."; std::vector BitRestorer::resourceCost={{PROCEDURE,6},{RANGE,1},{ATKSPD,1},{MOVESPD,1},{HEALTH,2}}; BitRestorer::BitRestorer(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) :Unit(pge,BitRestorer::resourceCost,pos,12,*IMAGES[BIT_RESTORER],CONSTANT::HEALER_TARGET_COL,CONSTANT::HEALER_ATTACK_COL,friendly,moveable,true,false){} diff --git a/olcCodeJam2023Entry/VirusAttack.cpp b/olcCodeJam2023Entry/VirusAttack.cpp index 5991ba6..3bfba1f 100644 --- a/olcCodeJam2023Entry/VirusAttack.cpp +++ b/olcCodeJam2023Entry/VirusAttack.cpp @@ -58,6 +58,10 @@ bool VirusAttack::OnUserCreate(){ InitializeImages(); + unitCreationBox.Initialize("Hello world, this is a test of the textbox system.\nMaybe even with some newline characters snuck in there.", + {}); + unitCreationBox.SetVisible(false); + IMAGES[MINIMAP_OUTLINE]=std::make_unique(); IMAGES[MINIMAP_OUTLINE]->Create(64,64); @@ -122,77 +126,50 @@ void VirusAttack::InitializeSounds(){ } bool VirusAttack::UnitCreationClickHandled(){ - if(leftShifterButton->bPressed){ - for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,LeftShifter::resourceCost)){ - std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); - u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); - ExpendResources(player_resources,LeftShifter::resourceCost); - } - } - return true; - } - if(rightShifterButton->bPressed){ - for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,RightShifter::resourceCost)){ - std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); - u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); - ExpendResources(player_resources,RightShifter::resourceCost); - } - } - return true; - } - if(bitRestorerButton->bPressed){ - for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,BitRestorer::resourceCost)){ - std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); - u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); - ExpendResources(player_resources,BitRestorer::resourceCost); - } - } - return true; - } - if(memorySwapperButton->bPressed){ - for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,MemorySwapper::resourceCost)){ - std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); - u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); - ExpendResources(player_resources,MemorySwapper::resourceCost); - } - } - return true; - } - if(corrupterButton->bPressed){ - for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,Corrupter::resourceCost)){ - std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); - u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); - ExpendResources(player_resources,Corrupter::resourceCost); - } - } - return true; - } - if(platformButton->bPressed){ - for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,MemoryAllocator::resourceCost)){ - std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); - u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); - ExpendResources(player_resources,MemoryAllocator::resourceCost); - } + #define CheckClick(UnitClass,Button) \ + if(Button->bPressed){ \ + for(auto&u:units){ \ + if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,UnitClass::resourceCost)) { \ + std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); \ + u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); \ + ExpendResources(player_resources,UnitClass::resourceCost); \ + } \ + } \ + return true; \ } - return true; - } + + CheckClick(LeftShifter,leftShifterButton) + CheckClick(RightShifter,rightShifterButton) + CheckClick(BitRestorer,bitRestorerButton) + CheckClick(MemorySwapper,memorySwapperButton) + CheckClick(BitRestorer,bitRestorerButton) + CheckClick(Corrupter,corrupterButton) + CheckClick(MemoryAllocator,platformButton) return false; }; void VirusAttack::UpdateUnitCreationListGUI(bool allocatorSelected){ unitCreationList.DisplayAllControls(allocatorSelected); - leftShifterButton->Enable(CanAfford(player_resources,LeftShifter::resourceCost)); - rightShifterButton->Enable(CanAfford(player_resources,RightShifter::resourceCost)); - bitRestorerButton->Enable(CanAfford(player_resources,BitRestorer::resourceCost)); - memorySwapperButton->Enable(CanAfford(player_resources,MemorySwapper::resourceCost)); - corrupterButton->Enable(CanAfford(player_resources,Corrupter::resourceCost)); - platformButton->Enable(CanAfford(player_resources,MemoryAllocator::resourceCost)); + #define EnableAndHoverCheck(UnitClass,Button) \ + Button->Enable(CanAfford(player_resources,UnitClass::resourceCost)); \ + if (Button->bHover) { \ + unitCreationBox.Initialize(UnitClass::unitDescription, GetMousePos(), UnitClass::unitName); \ + hovering=true; \ + } + + bool hovering=false; + EnableAndHoverCheck(LeftShifter,leftShifterButton) + EnableAndHoverCheck(RightShifter,rightShifterButton) + EnableAndHoverCheck(BitRestorer,bitRestorerButton) + EnableAndHoverCheck(MemorySwapper,memorySwapperButton) + EnableAndHoverCheck(BitRestorer,bitRestorerButton) + EnableAndHoverCheck(Corrupter,corrupterButton) + EnableAndHoverCheck(MemoryAllocator,platformButton) + + if(!hovering){ + unitCreationBox.SetVisible(false); + } + unitCreationList.Update(this); } @@ -556,6 +533,8 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ DrawMinimap(); + unitCreationBox.UpdateAndDraw(GetMousePos(),this,player_resources); + std::sort(units.begin(),units.end(),[&](auto&u1,auto&u2){ float dist1=geom2d::line(u1->GetGhostPos(),GetWorldMousePos()).length(); float dist2=geom2d::line(u2->GetGhostPos(),GetWorldMousePos()).length(); diff --git a/olcCodeJam2023Entry/VirusAttack.h b/olcCodeJam2023Entry/VirusAttack.h index 2d5c2c0..847b996 100644 --- a/olcCodeJam2023Entry/VirusAttack.h +++ b/olcCodeJam2023Entry/VirusAttack.h @@ -11,6 +11,7 @@ #include "DebuffIcon.h" #include "CollectionPoint.h" #include "Resources.h" +#include "Textbox.h" struct Letter{ vf2d pos; @@ -37,6 +38,8 @@ private: TileTransformedView game; + Textbox unitCreationBox; + QuickGUI::Manager unitCreationList; QuickGUI::ImageButton*leftShifterButton; QuickGUI::ImageButton*rightShifterButton; diff --git a/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj b/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj index 92b2a21..c091ed5 100644 --- a/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj +++ b/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj @@ -159,6 +159,7 @@ + @@ -169,6 +170,7 @@ + diff --git a/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj.filters b/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj.filters index 7095515..53714b6 100644 --- a/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj.filters +++ b/olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj.filters @@ -90,6 +90,9 @@ Header Files + + Header Files + @@ -116,6 +119,9 @@ Source Files + + Source Files + diff --git a/olcCodeJam2023Entry/olcPGEX_QuickGUI.h b/olcCodeJam2023Entry/olcPGEX_QuickGUI.h index 75f814b..e9747a8 100644 --- a/olcCodeJam2023Entry/olcPGEX_QuickGUI.h +++ b/olcCodeJam2023Entry/olcPGEX_QuickGUI.h @@ -80,6 +80,7 @@ namespace olc::QuickGUI { + enum class State { Disabled, Normal, Hover, Click }; class Manager; // Virtual base class for all controls @@ -101,6 +102,7 @@ namespace olc::QuickGUI bool bHeld = false; // True on single frame control ceases being manipulated bool bReleased = false; + bool bHover = false; public: // Updates the controls behvaiour @@ -111,6 +113,7 @@ namespace olc::QuickGUI virtual void DrawDecal(TileTransformedView&pge) = 0; virtual void Update(PixelGameEngine*pge); virtual void DrawDecal(PixelGameEngine*pge); + State m_state = State::Normal; protected: // Controls are related to a manager, where the theme resides @@ -122,7 +125,6 @@ namespace olc::QuickGUI // Normal - interactive and operational // Hover - currently under the users mouse focus // Click - user is interacting with the control - enum class State { Disabled, Normal, Hover, Click } m_state = State::Normal; // To add a "swish" to things, controls can fade between states float m_fTransition = 0.0; @@ -586,6 +588,7 @@ namespace olc::QuickGUI if (vMouse.x >= vPos.x && vMouse.x < vPos.x + vSize.x && vMouse.y >= vPos.y && vMouse.y < vPos.y + vSize.y) { + bHover = true; // Released inside box does nothing to me, but i may have // to finish off the neighbours... oo err bPressed = pge.GetPGE()->GetMouse(olc::Mouse::LEFT).bPressed; @@ -609,6 +612,7 @@ namespace olc::QuickGUI } else { + bHover = false; // Released outside box bPressed = pge.GetPGE()->GetMouse(olc::Mouse::LEFT).bPressed; bReleased = pge.GetPGE()->GetMouse(olc::Mouse::LEFT).bReleased; @@ -706,6 +710,7 @@ namespace olc::QuickGUI if (vMouse.x >= vPos.x && vMouse.x < vPos.x + vSize.x && vMouse.y >= vPos.y && vMouse.y < vPos.y + vSize.y) { + bHover = true; m_fTransition += fElapsedTime * m_manager.fHoverSpeedOn; m_state = State::Hover; @@ -719,6 +724,7 @@ namespace olc::QuickGUI } else { + bHover = false; m_fTransition -= fElapsedTime * m_manager.fHoverSpeedOff; m_state = State::Normal; } @@ -748,6 +754,7 @@ namespace olc::QuickGUI if (vMouse.x >= vPos.x && vMouse.x < vPos.x + vSize.x && vMouse.y >= vPos.y && vMouse.y < vPos.y + vSize.y) { + bHover = true; m_fTransition += fElapsedTime * m_manager.fHoverSpeedOn; m_state = State::Hover; @@ -761,6 +768,7 @@ namespace olc::QuickGUI } else { + bHover = false; m_fTransition -= fElapsedTime * m_manager.fHoverSpeedOff; m_state = State::Normal; } @@ -997,6 +1005,7 @@ namespace olc::QuickGUI olc::vf2d vSliderPos = vPosMin + (vPosMax - vPosMin) * ((fValue - fMin) / (fMax - fMin)); if ((vMouse - vSliderPos).mag2() <= int32_t(m_manager.fGrabRad) * int32_t(m_manager.fGrabRad)) { + bHover = true; m_fTransition += fElapsedTime * m_manager.fHoverSpeedOn; m_state = State::Hover; if (pge.GetPGE()->GetMouse(olc::Mouse::LEFT).bPressed) @@ -1005,8 +1014,10 @@ namespace olc::QuickGUI bPressed = true; } } - else + else{ + bHover = false; m_state = State::Normal; + } } if (pge.GetPGE()->GetMouse(olc::Mouse::LEFT).bReleased)