/src/MenuActionBar.cpp

http://github.com/clintbellanger/flare · C++ · 431 lines · 291 code · 68 blank · 72 comment · 95 complexity · 35c7c80d08de3567d7686d1cd108908e MD5 · raw file

  1. /*
  2. Copyright 2011 Clint Bellanger
  3. This file is part of FLARE.
  4. FLARE is free software: you can redistribute it and/or modify it under the terms
  5. of the GNU General Public License as published by the Free Software Foundation,
  6. either version 3 of the License, or (at your option) any later version.
  7. FLARE is distributed in the hope that it will be useful, but WITHOUT ANY
  8. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  9. PARTICULAR PURPOSE. See the GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License along with
  11. FLARE. If not, see http://www.gnu.org/licenses/
  12. */
  13. /**
  14. * class MenuActionBar
  15. *
  16. * Handles the config, display, and usage of the 0-9 hotkeys, mouse buttons, and menu calls
  17. */
  18. #include "MenuActionBar.h"
  19. #include "SharedResources.h"
  20. #include "WidgetLabel.h"
  21. #include <string>
  22. #include <sstream>
  23. using namespace std;
  24. MenuActionBar::MenuActionBar(PowerManager *_powers, StatBlock *_hero, SDL_Surface *_icons) {
  25. powers = _powers;
  26. hero = _hero;
  27. icons = _icons;
  28. src.x = 0;
  29. src.y = 0;
  30. src.w = 32;
  31. src.h = 32;
  32. label_src.x = 0;
  33. label_src.y = 0;
  34. label_src.w = 640;
  35. label_src.h = 10;
  36. drag_prev_slot = -1;
  37. clear();
  38. // TEMP: set action bar positions
  39. // TODO: define in a config file so that the menu is customizable
  40. int offset_x = (VIEW_W - 640)/2;
  41. int offset_y = VIEW_H-32;
  42. for (int i=0; i<12; i++) {
  43. slots[i].w = slots[i].h = 32;
  44. slots[i].y = VIEW_H-32;
  45. slots[i].x = offset_x + i*32 + 32;
  46. }
  47. slots[10].x += 32;
  48. slots[11].x += 32;
  49. // menu button positions
  50. for (int i=0; i<4; i++) {
  51. menus[i].w = menus[i].h = 32;
  52. menus[i].y = VIEW_H-32;
  53. menus[i].x = offset_x + 480 + i*32;
  54. }
  55. // screen areas occupied by the three main sections
  56. numberArea.h = mouseArea.h = menuArea.h = 32;
  57. numberArea.y = mouseArea.y = menuArea.y = offset_y;
  58. numberArea.x = offset_x+32;
  59. numberArea.w = 320;
  60. mouseArea.x = offset_x+384;
  61. mouseArea.w = 64;
  62. menuArea.x = offset_x+480;
  63. menuArea.w = 128;
  64. loadGraphics();
  65. }
  66. void MenuActionBar::clear() {
  67. // clear action bar
  68. for (int i=0; i<12; i++) {
  69. hotkeys[i] = -1;
  70. slot_item_count[i] = -1;
  71. slot_enabled[i] = true;
  72. }
  73. // clear menu notifications
  74. for (int i=0; i<4; i++)
  75. requires_attention[i] = false;
  76. // default: LMB set to basic melee attack
  77. hotkeys[10] = 1;
  78. }
  79. void MenuActionBar::loadGraphics() {
  80. emptyslot = IMG_Load(mods->locate("images/menus/slot_empty.png").c_str());
  81. background = IMG_Load(mods->locate("images/menus/actionbar_trim.png").c_str());
  82. labels = IMG_Load(mods->locate("images/menus/actionbar_labels.png").c_str());
  83. disabled = IMG_Load(mods->locate("images/menus/disabled.png").c_str());
  84. attention = IMG_Load(mods->locate("images/menus/attention_glow.png").c_str());
  85. if(!emptyslot || !background || !labels || !disabled) {
  86. fprintf(stderr, "Couldn't load image: %s\n", IMG_GetError());
  87. SDL_Quit();
  88. }
  89. // optimize
  90. SDL_Surface *cleanup = background;
  91. background = SDL_DisplayFormatAlpha(background);
  92. SDL_FreeSurface(cleanup);
  93. cleanup = emptyslot;
  94. emptyslot = SDL_DisplayFormatAlpha(emptyslot);
  95. SDL_FreeSurface(cleanup);
  96. cleanup = labels;
  97. labels = SDL_DisplayFormatAlpha(labels);
  98. SDL_FreeSurface(cleanup);
  99. cleanup = disabled;
  100. disabled = SDL_DisplayFormatAlpha(disabled);
  101. SDL_FreeSurface(cleanup);
  102. cleanup = attention;
  103. attention = SDL_DisplayFormatAlpha(attention);
  104. SDL_FreeSurface(cleanup);
  105. }
  106. /**
  107. * generic render 32-pixel icon
  108. */
  109. void MenuActionBar::renderIcon(int icon_id, int x, int y) {
  110. SDL_Rect icon_src;
  111. SDL_Rect icon_dest;
  112. icon_dest.x = x;
  113. icon_dest.y = y;
  114. icon_src.w = icon_src.h = icon_dest.w = icon_dest.h = 32;
  115. icon_src.x = (icon_id % 16) * 32;
  116. icon_src.y = (icon_id / 16) * 32;
  117. SDL_BlitSurface(icons, &icon_src, screen, &icon_dest);
  118. }
  119. // Renders the "needs attention" icon over the appropriate log menu
  120. void MenuActionBar::renderAttention(int menu_id) {
  121. SDL_Rect dest;
  122. // x-value is 12 hotkeys and 4 empty slots over
  123. dest.x = (VIEW_W - 640)/2 + (menu_id * 32) + 32*15;
  124. dest.y = VIEW_H-32;
  125. dest.w = dest.h = 32;
  126. SDL_BlitSurface(attention, NULL, screen, &dest);
  127. }
  128. void MenuActionBar::logic() {
  129. }
  130. void MenuActionBar::render() {
  131. SDL_Rect dest;
  132. SDL_Rect trimsrc;
  133. int offset_x = (VIEW_W - 640)/2;
  134. dest.x = offset_x;
  135. dest.y = VIEW_H-35;
  136. dest.w = 640;
  137. dest.h = 35;
  138. trimsrc.x = 0;
  139. trimsrc.y = 0;
  140. trimsrc.w = 640;
  141. trimsrc.h = 35;
  142. SDL_BlitSurface(background, &trimsrc, screen, &dest);
  143. // draw hotkeyed icons
  144. src.x = src.y = 0;
  145. src.w = src.h = dest.w = dest.h = 32;
  146. dest.y = VIEW_H-32;
  147. for (int i=0; i<12; i++) {
  148. if (i<=9)
  149. dest.x = offset_x + (i * 32) + 32;
  150. else
  151. dest.x = offset_x + (i * 32) + 64;
  152. if (hotkeys[i] != -1) {
  153. slot_enabled[i] = (hero->hero_cooldown[hotkeys[i]] == 0) && (slot_item_count[i] != 0); //see if the slot should be greyed out
  154. renderIcon(powers->powers[hotkeys[i]].icon, dest.x, dest.y);
  155. }
  156. else {
  157. SDL_BlitSurface(emptyslot, &src, screen, &dest);
  158. }
  159. }
  160. renderCooldowns();
  161. renderItemCounts();
  162. // render log attention notifications
  163. for (int i=0; i<4; i++)
  164. if (requires_attention[i])
  165. renderAttention(i);
  166. // draw hotkey labels
  167. // TODO: keybindings
  168. dest.x = offset_x;
  169. dest.y = VIEW_H-10;
  170. dest.w = 640;
  171. dest.h = 10;
  172. SDL_BlitSurface(labels, &label_src, screen, &dest);
  173. }
  174. /**
  175. * Display a notification for any power on cooldown
  176. * Also displays disabled powers
  177. */
  178. void MenuActionBar::renderCooldowns() {
  179. SDL_Rect item_src;
  180. SDL_Rect item_dest;
  181. for (int i=0; i<12; i++) {
  182. if (!slot_enabled[i]) {
  183. item_src.x = 0;
  184. item_src.y = 0;
  185. item_src.h = 32;
  186. item_src.w = 32;
  187. // Wipe from bottom to top
  188. if (hero->hero_cooldown[hotkeys[i]]) {
  189. item_src.h = 32 * (hero->hero_cooldown[hotkeys[i]] / (float)powers->powers[hotkeys[i]].cooldown);
  190. }
  191. // SDL_BlitSurface will write to these Rects, so make a copy
  192. item_dest.x = slots[i].x;
  193. item_dest.y = slots[i].y;
  194. item_dest.w = slots[i].w;
  195. item_dest.h = slots[i].h;
  196. SDL_BlitSurface(disabled, &item_src, screen, &item_dest);
  197. }
  198. }
  199. }
  200. /**
  201. * For powers that have consumables, display the number of consumables remaining
  202. */
  203. void MenuActionBar::renderItemCounts() {
  204. stringstream ss;
  205. for (int i=0; i<12; i++) {
  206. if (slot_item_count[i] > -1) {
  207. ss.str("");
  208. ss << slot_item_count[i];
  209. WidgetLabel label;
  210. label.set(slots[i].x, slots[i].y, JUSTIFY_LEFT, VALIGN_TOP, ss.str(), FONT_WHITE);
  211. label.render();
  212. }
  213. }
  214. }
  215. /**
  216. * On mouseover, show tooltip for buttons
  217. */
  218. TooltipData MenuActionBar::checkTooltip(Point mouse) {
  219. TooltipData tip;
  220. //int offset_x = (VIEW_W - 640)/2;
  221. if (isWithin(menus[0], mouse)) {
  222. tip.lines[tip.num_lines++] = msg->get("Character Menu (C)");
  223. return tip;
  224. }
  225. if (isWithin(menus[1], mouse)) {
  226. tip.lines[tip.num_lines++] = msg->get("Inventory Menu (I)");
  227. return tip;
  228. }
  229. if (isWithin(menus[2], mouse)) {
  230. tip.lines[tip.num_lines++] = msg->get("Power Menu (P)");
  231. return tip;
  232. }
  233. if (isWithin(menus[3], mouse)) {
  234. tip.lines[tip.num_lines++] = msg->get("Log Menu (L)");
  235. return tip;
  236. }
  237. for (int i=0; i<12; i++) {
  238. if (hotkeys[i] != -1) {
  239. if (isWithin(slots[i], mouse)) {
  240. tip.lines[tip.num_lines++] = powers->powers[hotkeys[i]].name;
  241. }
  242. }
  243. }
  244. return tip;
  245. }
  246. /**
  247. * After dragging a power or item onto the action bar, set as new hotkey
  248. */
  249. void MenuActionBar::drop(Point mouse, int power_index, bool rearranging) {
  250. for (int i=0; i<12; i++) {
  251. if (isWithin(slots[i], mouse)) {
  252. if (rearranging) {
  253. hotkeys[drag_prev_slot] = hotkeys[i];
  254. }
  255. hotkeys[i] = power_index;
  256. return;
  257. }
  258. }
  259. }
  260. /**
  261. * CTRL-click a hotkey to clear it
  262. */
  263. void MenuActionBar::remove(Point mouse) {
  264. for (int i=0; i<12; i++) {
  265. if (isWithin(slots[i], mouse)) {
  266. hotkeys[i] = -1;
  267. return;
  268. }
  269. }
  270. }
  271. /**
  272. * If pressing an action key (keyboard or mouseclick) and the power is enabled,
  273. * return that power's ID.
  274. */
  275. int MenuActionBar::checkAction(Point mouse) {
  276. // check click action
  277. if ((inp->pressing[MAIN1] && !inp->lock[MAIN1]) || (inp->pressing[MAIN2] && !inp->lock[MAIN2])) {
  278. for (int i=0; i<12; i++) {
  279. if (isWithin(slots[i], mouse) && slot_enabled[i]) {
  280. return hotkeys[i];
  281. }
  282. }
  283. }
  284. // check hotkey action
  285. if (inp->pressing[BAR_1] && slot_enabled[0]) return hotkeys[0];
  286. if (inp->pressing[BAR_2] && slot_enabled[1]) return hotkeys[1];
  287. if (inp->pressing[BAR_3] && slot_enabled[2]) return hotkeys[2];
  288. if (inp->pressing[BAR_4] && slot_enabled[3]) return hotkeys[3];
  289. if (inp->pressing[BAR_5] && slot_enabled[4]) return hotkeys[4];
  290. if (inp->pressing[BAR_6] && slot_enabled[5]) return hotkeys[5];
  291. if (inp->pressing[BAR_7] && slot_enabled[6]) return hotkeys[6];
  292. if (inp->pressing[BAR_8] && slot_enabled[7]) return hotkeys[7];
  293. if (inp->pressing[BAR_9] && slot_enabled[8]) return hotkeys[8];
  294. if (inp->pressing[BAR_0] && slot_enabled[9]) return hotkeys[9];
  295. if (inp->pressing[MAIN1] && slot_enabled[10] && !inp->lock[MAIN1]) {
  296. return hotkeys[10];
  297. }
  298. if (inp->pressing[MAIN2] && slot_enabled[11] && !inp->lock[MAIN2]) {
  299. return hotkeys[11];
  300. }
  301. return -1;
  302. }
  303. /**
  304. * If clicking while a menu is open, assume the player wants to rearrange the action bar
  305. */
  306. int MenuActionBar::checkDrag(Point mouse) {
  307. int power_index;
  308. for (int i=0; i<12; i++) {
  309. if (isWithin(slots[i], mouse)) {
  310. drag_prev_slot = i;
  311. power_index = hotkeys[i];
  312. hotkeys[i] = -1;
  313. return power_index;
  314. }
  315. }
  316. return -1;
  317. }
  318. /**
  319. * if clicking a menu, act as if the player pressed that menu's hotkey
  320. */
  321. void MenuActionBar::checkMenu(Point mouse, bool &menu_c, bool &menu_i, bool &menu_p, bool &menu_l) {
  322. if ((inp->pressing[MAIN1] && !inp->lock[MAIN1]) || (inp->pressing[MAIN2] && !inp->lock[MAIN2])) {
  323. if (isWithin(menus[MENU_CHARACTER], mouse)) {
  324. if (inp->pressing[MAIN1] && !inp->lock[MAIN1]) inp->lock[MAIN1] = true;
  325. else inp->lock[MAIN2] = true;
  326. menu_c = true;
  327. }
  328. else if (isWithin(menus[MENU_INVENTORY], mouse)) {
  329. if (inp->pressing[MAIN1] && !inp->lock[MAIN1]) inp->lock[MAIN1] = true;
  330. else inp->lock[MAIN2] = true;
  331. menu_i = true;
  332. }
  333. else if (isWithin(menus[MENU_POWERS], mouse)) {
  334. if (inp->pressing[MAIN1] && !inp->lock[MAIN1]) inp->lock[MAIN1] = true;
  335. else inp->lock[MAIN2] = true;
  336. inp->lock[MAIN1] = true;
  337. menu_p = true;
  338. }
  339. else if (isWithin(menus[MENU_LOG], mouse)) {
  340. if (inp->pressing[MAIN1] && !inp->lock[MAIN1]) inp->lock[MAIN1] = true;
  341. else inp->lock[MAIN2] = true;
  342. inp->lock[MAIN1] = true;
  343. menu_l = true;
  344. }
  345. }
  346. }
  347. /**
  348. * Set all hotkeys at once e.g. when loading a game
  349. */
  350. void MenuActionBar::set(int power_id[12]) {
  351. for (int i=0; i<12; i++)
  352. hotkeys[i] = power_id[i];
  353. }
  354. MenuActionBar::~MenuActionBar() {
  355. SDL_FreeSurface(emptyslot);
  356. SDL_FreeSurface(background);
  357. SDL_FreeSurface(labels);
  358. SDL_FreeSurface(disabled);
  359. }