guiButton.cxx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. // Filename: guiButton.cxx
  2. // Created by: cary (30Oct00)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. #include "guiButton.h"
  6. #include "config_gui.h"
  7. #include <throw_event.h>
  8. #include <map>
  9. typedef map<string, GuiButton*> ButtonMap;
  10. static ButtonMap buttons;
  11. TypeHandle GuiButton::_type_handle;
  12. static GuiButton *
  13. find_in_buttons_map(const string &name) {
  14. ButtonMap::const_iterator bi;
  15. bi = buttons.find(name);
  16. if (bi == buttons.end()) {
  17. return (GuiButton *)NULL;
  18. }
  19. return (*bi).second;
  20. }
  21. inline void GetExtents(GuiLabel* v, GuiLabel* w, GuiLabel* x, GuiLabel* y,
  22. GuiLabel* z, float& l, float& r, float& b, float& t) {
  23. float l1, l2, r1, r2, b1, b2, t1, t2;
  24. v->get_extents(l1, r1, b1, t1);
  25. w->get_extents(l2, r2, b2, t2);
  26. l1 = (l1<l2)?l1:l2;
  27. r1 = (r1<r2)?r2:r1;
  28. b1 = (b1<b2)?b1:b2;
  29. t1 = (t1<t2)?t2:t1;
  30. if (x != (GuiLabel*)0L) {
  31. x->get_extents(l2, r2, b2, t2);
  32. l1 = (l1<l2)?l1:l2;
  33. r1 = (r1<r2)?r2:r1;
  34. b1 = (b1<b2)?b1:b2;
  35. t1 = (t1<t2)?t2:t1;
  36. }
  37. if (y != (GuiLabel*)0L) {
  38. y->get_extents(l2, r2, b2, t2);
  39. l1 = (l1<l2)?l1:l2;
  40. r1 = (r1<r2)?r2:r1;
  41. b1 = (b1<b2)?b1:b2;
  42. t1 = (t1<t2)?t2:t1;
  43. }
  44. if (z != (GuiLabel*)0L) {
  45. z->get_extents(l2, r2, b2, t2);
  46. l = (l1<l2)?l1:l2;
  47. r = (r1<r2)?r2:r1;
  48. b = (b1<b2)?b1:b2;
  49. t = (t1<t2)?t2:t1;
  50. }
  51. }
  52. static void enter_button(CPT_Event e) {
  53. GuiButton* val = find_in_buttons_map(e->get_name());
  54. if (val == (GuiButton *)NULL) {
  55. if (gui_cat.is_debug()) {
  56. gui_cat.debug()
  57. << "Ignoring event " << e->get_name() << " for deleted button\n";
  58. }
  59. return;
  60. }
  61. val->test_ref_count_integrity();
  62. val->enter();
  63. }
  64. static void exit_button(CPT_Event e) {
  65. GuiButton* val = find_in_buttons_map(e->get_name());
  66. if (val == (GuiButton *)NULL) {
  67. if (gui_cat.is_debug()) {
  68. gui_cat.debug()
  69. << "Ignoring event " << e->get_name() << " for deleted button\n";
  70. }
  71. return;
  72. }
  73. val->test_ref_count_integrity();
  74. val->exit();
  75. }
  76. static void click_button_down(CPT_Event e) {
  77. GuiButton* val = find_in_buttons_map(e->get_name());
  78. if (val == (GuiButton *)NULL) {
  79. if (gui_cat.is_debug()) {
  80. gui_cat.debug()
  81. << "Ignoring event " << e->get_name() << " for deleted button\n";
  82. }
  83. return;
  84. }
  85. val->test_ref_count_integrity();
  86. val->down();
  87. }
  88. static void click_button_up(CPT_Event e) {
  89. GuiButton* val = find_in_buttons_map(e->get_name());
  90. if (val == (GuiButton *)NULL) {
  91. if (gui_cat.is_debug()) {
  92. gui_cat.debug()
  93. << "Ignoring event " << e->get_name() << " for deleted button\n";
  94. }
  95. return;
  96. }
  97. val->test_ref_count_integrity();
  98. val->up();
  99. }
  100. void GuiButton::switch_state(GuiButton::States nstate) {
  101. test_ref_count_integrity();
  102. // cleanup old state
  103. switch (_state) {
  104. case NONE:
  105. break;
  106. case UP:
  107. _mgr->remove_label(_up);
  108. break;
  109. case UP_ROLLOVER:
  110. _mgr->remove_label(_up_rollover);
  111. break;
  112. case DOWN:
  113. _mgr->remove_label(_down);
  114. break;
  115. case DOWN_ROLLOVER:
  116. _mgr->remove_label(_down_rollover);
  117. break;
  118. case INACTIVE:
  119. if (_inactive != (GuiLabel*)0L)
  120. _mgr->remove_label(_inactive);
  121. break;
  122. case INACTIVE_ROLLOVER:
  123. if (_inactive != (GuiLabel*)0L)
  124. _mgr->remove_label(_inactive);
  125. break;
  126. default:
  127. gui_cat->warning() << "switching away from invalid state (" << (int)_state
  128. << ")" << endl;
  129. }
  130. _state = nstate;
  131. // deal with new state
  132. switch (_state) {
  133. case NONE:
  134. _rgn->trap_clicks(false);
  135. break;
  136. case UP:
  137. _mgr->add_label(_up);
  138. if (!_up_event.empty())
  139. throw_event(_up_event);
  140. _rgn->trap_clicks(true);
  141. break;
  142. case UP_ROLLOVER:
  143. if (_up_rollover != (GuiLabel*)0L) {
  144. _mgr->add_label(_up_rollover);
  145. if (!_up_rollover_event.empty())
  146. throw_event(_up_rollover_event);
  147. } else {
  148. _mgr->add_label(_up);
  149. if (!_up_event.empty())
  150. throw_event(_up_event);
  151. _state = UP;
  152. }
  153. _rgn->trap_clicks(true);
  154. break;
  155. case DOWN:
  156. _mgr->add_label(_down);
  157. if (!_down_event.empty())
  158. throw_event(_down_event);
  159. _rgn->trap_clicks(true);
  160. break;
  161. case DOWN_ROLLOVER:
  162. if (_down_rollover != (GuiLabel*)0L) {
  163. _mgr->add_label(_down_rollover);
  164. if (!_down_rollover_event.empty())
  165. throw_event(_down_rollover_event);
  166. } else {
  167. _mgr->add_label(_down);
  168. if (!_down_event.empty())
  169. throw_event(_down_event);
  170. _state = DOWN;
  171. }
  172. _rgn->trap_clicks(true);
  173. break;
  174. case INACTIVE:
  175. if (_inactive != (GuiLabel*)0L) {
  176. _mgr->add_label(_inactive);
  177. if (!_inactive_event.empty())
  178. throw_event(_inactive_event);
  179. }
  180. _rgn->trap_clicks(false);
  181. break;
  182. case INACTIVE_ROLLOVER:
  183. if (_inactive != (GuiLabel*)0L) {
  184. _mgr->add_label(_inactive);
  185. if (!_inactive_event.empty())
  186. throw_event(_inactive_event);
  187. }
  188. _rgn->trap_clicks(false);
  189. break;
  190. default:
  191. gui_cat->warning() << "switched to invalid state (" << (int)_state << ")"
  192. << endl;
  193. }
  194. }
  195. void GuiButton::recompute_frame(void) {
  196. GuiBehavior::recompute_frame();
  197. _up->recompute();
  198. _down->recompute();
  199. if (_up_rollover != (GuiLabel*)0L)
  200. _up_rollover->recompute();
  201. if (_down_rollover != (GuiLabel*)0L)
  202. _down_rollover->recompute();
  203. if (_inactive != (GuiLabel*)0L)
  204. _inactive->recompute();
  205. GetExtents(_up, _down, _up_rollover, _down_rollover, _inactive, _left,
  206. _right, _bottom, _top);
  207. _rgn->set_region(_left, _right, _bottom, _top);
  208. }
  209. void GuiButton::behavior_up(CPT_Event, void* data) {
  210. GuiButton* button = (GuiButton*)data;
  211. button->run_button_up();
  212. }
  213. void GuiButton::behavior_down(CPT_Event, void* data) {
  214. GuiButton* button = (GuiButton*)data;
  215. button->run_button_down();
  216. }
  217. void GuiButton::run_button_up(void) {
  218. if (_eh == (EventHandler*)0L)
  219. return;
  220. _eh->remove_hook(_up_event, GuiButton::behavior_up, (void*)this);
  221. _eh->remove_hook(_up_rollover_event, GuiButton::behavior_up, (void*)this);
  222. if (!_behavior_event.empty())
  223. throw_event(_behavior_event);
  224. if (_behavior_functor != (GuiBehavior::BehaviorFunctor*)0L)
  225. _behavior_functor->doit(this);
  226. }
  227. void GuiButton::run_button_down(void) {
  228. if (_eh == (EventHandler*)0L)
  229. return;
  230. _eh->add_hook(_up_event, GuiButton::behavior_up, (void*)this);
  231. _eh->add_hook(_up_rollover_event, GuiButton::behavior_up, (void*)this);
  232. }
  233. GuiButton::GuiButton(const string& name, GuiLabel* up, GuiLabel* down)
  234. : GuiBehavior(name), _up(up), _up_rollover((GuiLabel*)0L), _down(down),
  235. _down_rollover((GuiLabel*)0L), _inactive((GuiLabel*)0L),
  236. _up_event(name + "-up"), _up_rollover_event(""),
  237. _down_event(name +"-down"), _down_rollover_event(""),
  238. _inactive_event(""), _up_scale(up->get_scale()), _upr_scale(1.),
  239. _down_scale(down->get_scale()), _downr_scale(1.), _inactive_scale(1.),
  240. _state(GuiButton::NONE),
  241. _behavior_functor((GuiBehavior::BehaviorFunctor*)0L) {
  242. GetExtents(up, down, _up_rollover, _down_rollover, _inactive, _left, _right,
  243. _bottom, _top);
  244. _rgn = new GuiRegion("button-" + name, _left, _right, _bottom, _top, true);
  245. buttons["gui-in-button-" + name] = this;
  246. buttons["gui-out-button-" + name] = this;
  247. buttons["gui-button-" + name + "-mouse1"] = this;
  248. buttons["gui-button-" + name + "-mouse2"] = this;
  249. buttons["gui-button-" + name + "-mouse3"] = this;
  250. buttons["gui-button-" + name + "-mouse1-up"] = this;
  251. buttons["gui-button-" + name + "-mouse2-up"] = this;
  252. buttons["gui-button-" + name + "-mouse3-up"] = this;
  253. }
  254. GuiButton::GuiButton(const string& name, GuiLabel* up, GuiLabel* down,
  255. GuiLabel* inactive)
  256. : GuiBehavior(name), _up(up), _up_rollover((GuiLabel*)0L), _down(down),
  257. _down_rollover((GuiLabel*)0L), _inactive(inactive),
  258. _up_event(name + "-up"), _up_rollover_event(""),
  259. _down_event(name +"-down"), _down_rollover_event(""),
  260. _inactive_event(name + "-inactive"), _up_scale(up->get_scale()),
  261. _upr_scale(1.), _down_scale(down->get_scale()), _downr_scale(1.),
  262. _inactive_scale(inactive->get_scale()), _state(GuiButton::NONE),
  263. _behavior_functor((GuiBehavior::BehaviorFunctor*)0L) {
  264. GetExtents(up, down, _up_rollover, _down_rollover, inactive, _left, _right,
  265. _bottom, _top);
  266. _rgn = new GuiRegion("button-" + name, _left, _right, _bottom, _top, true);
  267. buttons["gui-in-button-" + name] = this;
  268. buttons["gui-out-button-" + name] = this;
  269. buttons["gui-button-" + name + "-mouse1"] = this;
  270. buttons["gui-button-" + name + "-mouse2"] = this;
  271. buttons["gui-button-" + name + "-mouse3"] = this;
  272. buttons["gui-button-" + name + "-mouse1-up"] = this;
  273. buttons["gui-button-" + name + "-mouse2-up"] = this;
  274. buttons["gui-button-" + name + "-mouse3-up"] = this;
  275. }
  276. GuiButton::GuiButton(const string& name, GuiLabel* up, GuiLabel* up_roll,
  277. GuiLabel* down, GuiLabel* down_roll, GuiLabel* inactive)
  278. : GuiBehavior(name), _up(up), _up_rollover(up_roll), _down(down),
  279. _down_rollover(down_roll), _inactive(inactive), _up_event(name + "-up"),
  280. _up_rollover_event(name + "-up-rollover"), _down_event(name +"-down"),
  281. _down_rollover_event(name + "-down-rollover"),
  282. _inactive_event(name + "-inactive"), _up_scale(up->get_scale()),
  283. _upr_scale(up_roll->get_scale()), _down_scale(down->get_scale()),
  284. _downr_scale(down_roll->get_scale()),
  285. _inactive_scale(inactive->get_scale()), _state(GuiButton::NONE),
  286. _behavior_functor((GuiBehavior::BehaviorFunctor*)0L) {
  287. GetExtents(up, down, up_roll, down_roll, inactive, _left, _right, _bottom,
  288. _top);
  289. _rgn = new GuiRegion("button-" + name, _left, _right, _bottom, _top, true);
  290. buttons["gui-in-button-" + name] = this;
  291. buttons["gui-out-button-" + name] = this;
  292. buttons["gui-button-" + name + "-mouse1"] = this;
  293. buttons["gui-button-" + name + "-mouse2"] = this;
  294. buttons["gui-button-" + name + "-mouse3"] = this;
  295. buttons["gui-button-" + name + "-mouse1-up"] = this;
  296. buttons["gui-button-" + name + "-mouse2-up"] = this;
  297. buttons["gui-button-" + name + "-mouse3-up"] = this;
  298. }
  299. GuiButton::~GuiButton(void) {
  300. this->unmanage();
  301. // Remove the names from the buttons map, so we don't end up with
  302. // an invalid pointer.
  303. string name = get_name();
  304. buttons.erase("gui-in-button-" + name);
  305. buttons.erase("gui-out-button-" + name);
  306. buttons.erase("gui-button-" + name + "-mouse1");
  307. buttons.erase("gui-button-" + name + "-mouse2");
  308. buttons.erase("gui-button-" + name + "-mouse3");
  309. buttons.erase("gui-button-" + name + "-mouse1-up");
  310. buttons.erase("gui-button-" + name + "-mouse2-up");
  311. buttons.erase("gui-button-" + name + "-mouse3-up");
  312. if (_behavior_functor != (GuiBehavior::BehaviorFunctor*)0L)
  313. delete _behavior_functor;
  314. }
  315. void GuiButton::manage(GuiManager* mgr, EventHandler& eh) {
  316. if (!_added_hooks) {
  317. eh.add_hook("gui-in-button-" + get_name(), enter_button);
  318. eh.add_hook("gui-out-button-" + get_name(), exit_button);
  319. eh.add_hook("gui-button-" + get_name() + "-mouse1", click_button_down);
  320. eh.add_hook("gui-button-" + get_name() + "-mouse2", click_button_down);
  321. eh.add_hook("gui-button-" + get_name() + "-mouse3", click_button_down);
  322. eh.add_hook("gui-button-" + get_name() + "-mouse1-up", click_button_up);
  323. eh.add_hook("gui-button-" + get_name() + "-mouse2-up", click_button_up);
  324. eh.add_hook("gui-button-" + get_name() + "-mouse3-up", click_button_up);
  325. _added_hooks = true;
  326. }
  327. if (_mgr == (GuiManager*)0L) {
  328. mgr->add_region(_rgn);
  329. GuiBehavior::manage(mgr, eh);
  330. if (_behavior_running)
  331. this->start_behavior();
  332. switch_state(UP);
  333. } else
  334. gui_cat->warning() << "tried to manage button (0x" << (void*)this
  335. << ") that is already managed" << endl;
  336. }
  337. void GuiButton::unmanage(void) {
  338. if (_mgr != (GuiManager*)0L)
  339. _mgr->remove_region(_rgn);
  340. if (_behavior_running)
  341. this->stop_behavior();
  342. switch_state(NONE);
  343. GuiBehavior::unmanage();
  344. }
  345. int GuiButton::freeze() {
  346. _up->freeze();
  347. _down->freeze();
  348. if (_up_rollover != (GuiLabel*)0L)
  349. _up_rollover->freeze();
  350. if (_down_rollover != (GuiLabel*)0L)
  351. _down_rollover->freeze();
  352. if (_inactive != (GuiLabel*)0L)
  353. _inactive->freeze();
  354. return 0;
  355. }
  356. int GuiButton::thaw() {
  357. _up->thaw();
  358. _down->thaw();
  359. if (_up_rollover != (GuiLabel*)0L)
  360. _up_rollover->thaw();
  361. if (_down_rollover != (GuiLabel*)0L)
  362. _down_rollover->thaw();
  363. if (_inactive != (GuiLabel*)0L)
  364. _inactive->thaw();
  365. return 0;
  366. }
  367. void GuiButton::set_scale(float f) {
  368. _up->set_scale(f * _up_scale);
  369. _down->set_scale(f * _down_scale);
  370. if (_up_rollover != (GuiLabel*)0L)
  371. _up_rollover->set_scale(f * _upr_scale);
  372. if (_down_rollover != (GuiLabel*)0L)
  373. _down_rollover->set_scale(f * _downr_scale);
  374. if (_inactive != (GuiLabel*)0L)
  375. _inactive->set_scale(f * _inactive_scale);
  376. GuiBehavior::set_scale(f);
  377. this->recompute_frame();
  378. }
  379. void GuiButton::set_pos(const LVector3f& p) {
  380. _up->set_pos(p);
  381. _down->set_pos(p);
  382. if (_up_rollover != (GuiLabel*)0L)
  383. _up_rollover->set_pos(p);
  384. if (_down_rollover != (GuiLabel*)0L)
  385. _down_rollover->set_pos(p);
  386. if (_inactive != (GuiLabel*)0L)
  387. _inactive->set_pos(p);
  388. GuiBehavior::set_pos(p);
  389. this->recompute_frame();
  390. }
  391. void GuiButton::start_behavior(void) {
  392. GuiBehavior::start_behavior();
  393. if (_mgr == (GuiManager*)0L)
  394. return;
  395. _eh->add_hook(_down_event, GuiButton::behavior_down, (void*)this);
  396. _eh->add_hook(_down_rollover_event, GuiButton::behavior_down, (void*)this);
  397. }
  398. void GuiButton::stop_behavior(void) {
  399. GuiBehavior::stop_behavior();
  400. if (_mgr == (GuiManager*)0L)
  401. return;
  402. _eh->remove_hook(_up_event, GuiButton::behavior_up, (void*)this);
  403. _eh->remove_hook(_up_rollover_event, GuiButton::behavior_up, (void*)this);
  404. _eh->remove_hook(_down_event, GuiButton::behavior_down, (void*)this);
  405. _eh->remove_hook(_down_rollover_event, GuiButton::behavior_down,
  406. (void*)this);
  407. }
  408. void GuiButton::reset_behavior(void) {
  409. GuiBehavior::reset_behavior();
  410. if (_mgr == (GuiManager*)0L)
  411. return;
  412. _eh->remove_hook(_up_event, GuiButton::behavior_up, (void*)this);
  413. _eh->remove_hook(_up_rollover_event, GuiButton::behavior_up, (void*)this);
  414. }
  415. void GuiButton::output(ostream& os) const {
  416. GuiBehavior::output(os);
  417. os << " Button data:" << endl;
  418. os << " up - 0x" << (void*)_up << endl;
  419. os << " up_rollover - 0x" << (void*)_up_rollover << endl;
  420. os << " down - 0x" << (void*)_down << endl;
  421. os << " down_rollover - 0x" << (void*)_down_rollover << endl;
  422. os << " inactive - 0x" << (void*)_inactive << endl;
  423. os << " up event - '" << _up_event << "'" << endl;
  424. os << " up_rollover event - '" << _up_rollover_event << "'" << endl;
  425. os << " down event - '" << _down_event << "'" << endl;
  426. os << " down_rollover event - '" << _down_rollover_event << "'" << endl;
  427. os << " inactive event - '" << _inactive_event << "'" << endl;
  428. os << " rgn - 0x" << (void*)_rgn << endl;
  429. os << " frame - " << _rgn->get_frame() << endl;
  430. os << " state - " << (int)_state << endl;
  431. }