From 8c055cbdddac2114c130e6a6524ff887d89ccf53 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Wed, 8 Aug 2012 22:47:20 +0200 Subject: [PATCH] added rough implementation of a Menu --- src/battle/BattleState.cpp | 9 ++ src/battle/BattleState.h | 3 + src/battle/states/SelectSpell.cpp | 12 ++- src/battle/states/SelectSpell.h | 6 ++ src/graphics/Menu.h | 146 ++++++++++++++++++++++++++++++ src/main.cpp | 3 + test-data/normal-font.png | Bin 1249 -> 1266 bytes 7 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 src/graphics/Menu.h diff --git a/src/battle/BattleState.cpp b/src/battle/BattleState.cpp index ae882a6..15d9d18 100644 --- a/src/battle/BattleState.cpp +++ b/src/battle/BattleState.cpp @@ -20,6 +20,7 @@ using app::Application; using app::Input; using geometry::Point; using geometry::Vector; +using graphics::Menu; using std::vector; @@ -50,6 +51,14 @@ void BattleState::EnterState(Application &ctrl, SDL_Surface *screen) { heroesLayout->CalculatePositions(background->w, background->h, heroesPositions); attackChoices.resize(heroes.size()); for (vector::size_type i(0), end(heroes.size()); i < end; ++i) { + // TODO: extract menu dimensions to resources + Menu spellMenu(res->normalFont, 12, 6, 8, 2, 32); + spellMenu.Add("Strong : 3", 0); + spellMenu.Add("Stronger : 8", 0); + spellMenu.Add("Champion :16", 0); + spellMenu.Add("Rally :10", 0); + spellMenu.Add("Valor :30", 0); + spellMenus.push_back(spellMenu); heroTags.push_back(HeroTag(&heroes[i], &attackChoices[i], res, HeroTag::Alignment((i + 1) % 2))); } } diff --git a/src/battle/BattleState.h b/src/battle/BattleState.h index 484e452..365f198 100644 --- a/src/battle/BattleState.h +++ b/src/battle/BattleState.h @@ -18,6 +18,7 @@ #include "../app/State.h" #include "../geometry/Point.h" #include "../geometry/Vector.h" +#include "../graphics/Menu.h" #include #include @@ -77,6 +78,7 @@ public: bool HasChosenAttackType() const { return attackChoices[activeHero].GetType() != AttackChoice::UNDECIDED; } void SetAttackType(AttackChoice::Type t) { attackChoices[activeHero].SetType(t); } bool AttackSelectionDone() const { return activeHero >= (int) heroes.size(); } + const graphics::Menu GetSpellMenu() const { return spellMenus[activeHero]; } public: geometry::Vector CalculateScreenOffset(SDL_Surface *screen) const { @@ -103,6 +105,7 @@ private: std::vector > heroesPositions; std::vector monsters; std::vector heroes; + std::vector > spellMenus; std::vector heroTags; std::vector attackChoices; int activeHero; diff --git a/src/battle/states/SelectSpell.cpp b/src/battle/states/SelectSpell.cpp index 1b01250..5f358fb 100644 --- a/src/battle/states/SelectSpell.cpp +++ b/src/battle/states/SelectSpell.cpp @@ -63,13 +63,23 @@ void SelectSpell::UpdateWorld(float deltaT) { void SelectSpell::Render(SDL_Surface *screen) { parent->Render(screen); + Vector offset(battle->CalculateScreenOffset(screen)); + RenderFrame(screen, offset); + RenderMenu(screen, offset); +} + +void SelectSpell::RenderFrame(SDL_Surface *screen, const Vector &offset) { const Frame *frame(battle->Res().selectFrame); Point position(frame->BorderWidth(), frame->BorderHeight()); - Vector offset(battle->CalculateScreenOffset(screen)); int width(battle->BackgroundWidth() - 2 * frame->BorderWidth()); // TODO: replace with font height int height(frame->BorderHeight() * 13); frame->Draw(screen, position + offset, width, height); } +void SelectSpell::RenderMenu(SDL_Surface *screen, const Vector &offset) { + Point position(2 * battle->Res().selectFrame->BorderWidth(), 2 * battle->Res().selectFrame->BorderHeight()); + battle->GetSpellMenu().Draw(screen, position + offset); +} + } diff --git a/src/battle/states/SelectSpell.h b/src/battle/states/SelectSpell.h index e0bb118..f3841a1 100644 --- a/src/battle/states/SelectSpell.h +++ b/src/battle/states/SelectSpell.h @@ -10,6 +10,8 @@ #include "../../app/State.h" +#include "../../geometry/Vector.h" + namespace battle { class BattleState; @@ -34,6 +36,10 @@ public: virtual void UpdateWorld(float deltaT); virtual void Render(SDL_Surface *); +private: + void RenderFrame(SDL_Surface *, const geometry::Vector &offset); + void RenderMenu(SDL_Surface *, const geometry::Vector &offset); + private: app::Application *ctrl; BattleState *battle; diff --git a/src/graphics/Menu.h b/src/graphics/Menu.h new file mode 100644 index 0000000..0a4a698 --- /dev/null +++ b/src/graphics/Menu.h @@ -0,0 +1,146 @@ +/* + * Menu.h + * + * Created on: Aug 8, 2012 + * Author: holy + */ + +#ifndef GRAPHICS_MENU_H_ +#define GRAPHICS_MENU_H_ + +#include "Font.h" +#include "../geometry/operators.h" +#include "../geometry/Point.h" +#include "../geometry/Vector.h" + +#include +#include + +namespace graphics { + +class Sprite; + +template +class Menu { + +public: + Menu(const Font *font, int charsPerEntry, int rows, int rowGap = 0, int cols = 1, int colGap = 0); + +public: + int Width() const; + int Height() const; + int ColWidth() const { return font->CharWidth() * charsPerEntry; } + int RowHeight() const { return font->CharHeight() + rowGap; } + + T &Selected() { return entries[selected].value; } + const T &Selected() const { return entries[selected].value; } + const char *SelectedTitle() const { return entries[selected].title; } + + void NextItem(); + void PreviousItem(); + void NextRow(); + void PreviousRow(); + void SelectIndex(int index); + + void Add(const char *title, const T &value, const Sprite *icon = 0) { entries.push_back(Entry(title, value, icon)); } + void Reserve(int n) { entries.reserve(n); } + + void Draw(SDL_Surface *dest, geometry::Point position) const; + +private: + int GetRow(int index) const { return index / cols; } + int GetCol(int index) const { return index % cols; } + +private: + struct Entry { + Entry(const char *title, const T &value, const Sprite *icon = 0) + : title(title), icon(icon), value(value) { } + const char *title; + const Sprite *icon; + T value; + }; + const Font *font; + std::vector entries; + int charsPerEntry; + int rows; + int rowGap; + int cols; + int colGap; + int selected; + int topRow; + +}; + + +template +Menu::Menu(const Font *font, int charsPerEntry, int rows, int rowGap, int cols, int colGap) +: font(font) +, charsPerEntry(charsPerEntry) +, rows(rows) +, rowGap(rowGap) +, cols(cols) +, colGap(colGap) +, selected(0) +, topRow(0) { + +} + + +template +int Menu::Width() const { + return cols * ColWidth() + (cols - 1) * colGap; +} + +template +int Menu::Height() const { + return rows * font->CharHeight() + (rows - 1) * rowGap; +} + + +template +void Menu::NextItem() { + SelectIndex(selected + 1); +} + +template +void Menu::PreviousItem() { + SelectIndex(selected - 1); +} + +template +void Menu::NextRow() { + SelectIndex(selected + cols); +} + +template +void Menu::PreviousRow() { + SelectIndex(selected - cols); +} + +template +void Menu::SelectIndex(int index) { + if (index < 0 || entries.size() < index) return; + selected = index; + if (GetRow(selected) - rows > topRow) { + topRow = GetRow(selected) - rows; + } else if (GetRow(selected) < topRow) { + topRow = GetRow(selected); + } +} + + +template +void Menu::Draw(SDL_Surface *dest, geometry::Point position) const { + int start(topRow * cols); + int slots((topRow + rows) * cols); + int items(entries.size() - start); + int end(items < slots ? items : slots); + for (int i(0), count(end - start); i < count; ++i) { + geometry::Vector offset((i % cols) * (ColWidth() + colGap), (i / cols) * RowHeight()); + font->DrawString(entries[start + i].title, dest, position + offset, charsPerEntry); + } +} + +} + +#endif /* GRAPHICS_MENU_H_ */ diff --git a/src/main.cpp b/src/main.cpp index d9a2f57..676f2d7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -161,6 +161,9 @@ int main(int argc, char **argv) { normalFont.MapRange('N', 'Z', 0, 2); normalFont.MapRange('a', 'm', 0, 3); normalFont.MapRange('n', 'z', 0, 4); + normalFont.MapChar(':', 10, 0); + normalFont.MapChar('!', 10, 0); + normalFont.MapChar('?', 10, 0); battleRes.normalFont = &normalFont; BattleState *battleState(new BattleState(bg, monstersLayout, heroesLayout, &battleRes)); diff --git a/test-data/normal-font.png b/test-data/normal-font.png index b2b1a40927bbccd470302247b7220bf403c81000..0bd50d02efb6c249d24a7431c9d0bf4214965010 100644 GIT binary patch delta 1246 zcmV<41R?w33GxY$B!9U{L_t(|+U=c9lH4E+M!QpUfm!7K2h3uQFj@5?T}AZwNnp== zn^Y3pfN|?XNWk;4;QRag`|%&1&*$^u;Po8u^{Vn!^Q4=#To;vd>FNllC_lH zc6mn*tLJ1#9#bPA)od`cZ~%8!psMAlDvf19SNE&pW4nAA)ht?7VO4RUZXXE+0=Sa` zRV^#CSZCLFx_>_1v$`k{K;;LP9iysqxV+^?eH@i#^0r5nsc_d^#9eVURlnl{0RR91 z+}8(+j-jV~m(~66af21BctSREUX8q~+VQ&28!xf0@AhF;RAL1CZ}dK zpRy-|*N4mcMrx%}^=EdMpIzSr3Iw23Al1%|Q)A_*WxD$8+fU=P*Z&B8`==BD}&1p)v70Jt1a?-+MA){Krt?|!aM z)`wB8N7|JQf0z65fdB?cpAS@3rtFTE)^m21UtQ1By;t|~Lm|=1)N1+Ben)`-lnSI? zA*y=*>E%Z`EfZq50$BBk#-Y^pU)_fS0Vow{w|}MHy`Csr{%M&6r;z=Avfp1;!Ls#7 zfdD!bXqOUoD@)g|LQ!QoH7i_g!BzdGQX=*Df&u|_D$wc|Jv|FjwK(0DlyyeEBZVm? zj6NR)0;m}7>@Tk?7fu})>Kfy(u2;{(W$UH#HLK-&Ps{F#J9h2ujsgJy003Oy2ii4@ zv44xHdREWq+}*C}b9bzrSG}m7gAWAI$Oo@rNa`=To@aWe)@V*)_j6DnfJp_a?yF|` z0A9<~bxJ~ZEM9#NRo^LV;Z^THn@grv;I51hZ`|7wm_GGBG zFM7)LbmUyMH^i>f%cqpbQfBKrMS%b&eSe^?*_SE2ma+OCcJIA#mtA~LKXDHQ0#GWD z`}gg3j#^R76M_x`SPhPrdqRI`1m`gi5R zSxOW=LpJ(8nS}%BP#`!1OF>VaWt+}E#|Huc0002Ej}JsF2puFSbAE@qox4@@URad~(EUNlc3=|09Bn9&B2x(b@?j13^6iOAxQuzSc z{>heKJ%6b>OIP*jSGy^pKmZ*>^{b41uUZbwGIc5g3IrhFFC%lrswS7)&Hw-a07*qo IM6N<$f>)k!$N&HU delta 1229 zcmV;;1Ty>b3E>HlB!8$$L_t(|+U=b|lH4E+Mcb*qz$|kA17~yS-=g*Z z^8kP_&!}Qp*Uef&Rr#v=kFN8!D{En+%AHk+-QK@Sd7|I#sDFL$KT#k6r2?s#wb&}l zt+Hs<7IL-nbhqmiX5R}61hAt5RgY=2vnkdXSmnd0eUzxB^tQ`8au_`)I`Zfm0jXw# znS}$mvjSx;M^24Wfk@m9|;8lxRU~9Ei1EFd)K$SKGn0jC=fvA z2NoTps$;mKV}IkSSgvS$RFMjIjYV9wuBPgDd>{Y-0D$}YK(k}$F5hKz|M$Od*L`1q zzogOQ*_C%yJKpz=+V_cdeYFoWigM4c+jY&}5{(TY;Hk0@vlc4)e9K~37TB`9tD?cx z3X&e01p7rzclomsDkucW>TEQhvvi}`xYLzqHQo^y3ItH$16BJbyGAwdl9R#f!$o}~wNk12Gn(aR z)%Sn`0VownmASENtUPO(PM>}IZR|Gtivj^uDv(MUX2+JQ%%9fS-cp|KJa%5+ChF^` z`q7&Mp?_)?b~a|NtN&0S0001hZ|g&`9`v zpsX@QGg?~DSyg^^KTmb8?(K&{qMfPP@@M-U1p-hika~xx>iN5uKg({B5UUlys>kd) zl)C<-`%oYNr2?(C)T{RsMa$nUl3*92-%s@Wi+?IuwEid%K!pOWQle^Qsmdxet1P=l zg{v*Ns=ri9r2bw|Ab?5*8vUZXXF;+Sr`nRT&!~2!(4~a4&qsj(GKM?)%d3ioQ?CnE zjqyjKQj zz5i$|nOcFXB0jw9hM)hA0s$x$D0{}}=P!CT@}MgxL$-ahr(AchoU3v}tUA5COL;71 zw!Tvo2%ysks+xW2!fP3`?_qWBg}Y?&*?;}SJroE)sX&%5bov>bURLevQTq;e>xbR; zU7gFrO>D(HzgK)`7hDSDiCd9iyh2?NimiDi+RCqS-TKXWu8YZ~zqw1bbj9 z=&rMD-O=axKmY&$008&#fmjQ|2LiY?!*w8QN1r!Zd4xBLd06qHbtF~$qvdC3-+!{v z