text_array_object.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. // SuperTux
  2. // Copyright (C) 2018 Nir <goproducti@gmail.com>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. #include "object/text_array_object.hpp"
  17. #include <simplesquirrel/class.hpp>
  18. #include <simplesquirrel/vm.hpp>
  19. #include "control/input_manager.hpp"
  20. #include "supertux/sector.hpp"
  21. TextArrayObject::TextArrayObject(const std::string& name) :
  22. LayerObject(name),
  23. m_finished(false),
  24. m_is_auto(false),
  25. m_keep_visible(false),
  26. m_fade_transition(true),
  27. m_fadetime(1.0),
  28. m_texts(),
  29. m_curTextIndex(0),
  30. m_lastTextIndex(0),
  31. m_waiting()
  32. {
  33. }
  34. void
  35. TextArrayObject::clear()
  36. {
  37. m_texts.clear();
  38. reset_automation();
  39. }
  40. void
  41. TextArrayObject::add_text(const std::string& text)
  42. {
  43. add_text_duration(text, 3.f);
  44. }
  45. void
  46. TextArrayObject::add_text_duration(const std::string& text, float duration)
  47. {
  48. auto pText = std::make_unique<TextArrayItem>();
  49. assert(pText);
  50. pText->duration = duration;
  51. pText->text_object.set_text(text);
  52. m_texts.push_back(std::move(pText));
  53. }
  54. void
  55. TextArrayObject::set_text_index(ta_index index)
  56. {
  57. if (index < m_texts.size())
  58. m_curTextIndex = index;
  59. }
  60. void
  61. TextArrayObject::next_text()
  62. {
  63. if (m_finished)
  64. return;
  65. if (m_curTextIndex + 1 >= m_texts.size()) {
  66. m_finished = true;
  67. return;
  68. }
  69. m_lastTextIndex = m_curTextIndex++;
  70. override_properties();
  71. reset_automation();
  72. }
  73. void
  74. TextArrayObject::prev_text()
  75. {
  76. if (m_finished)
  77. return;
  78. if (m_curTextIndex == 0)
  79. return;
  80. m_lastTextIndex = m_curTextIndex--;
  81. override_properties();
  82. reset_automation();
  83. }
  84. TextArrayItem*
  85. TextArrayObject::get_text_item(ta_index index) const
  86. {
  87. auto vecSize = m_texts.size();
  88. if (vecSize == 0 || index >= vecSize)
  89. return nullptr;
  90. return m_texts.at(index).get();
  91. }
  92. TextArrayItem*
  93. TextArrayObject::get_current_text_item() const
  94. {
  95. return get_text_item(m_curTextIndex);
  96. }
  97. TextArrayItem*
  98. TextArrayObject::get_last_text_item() const
  99. {
  100. return get_text_item(m_lastTextIndex);
  101. }
  102. void
  103. TextArrayObject::set_auto(bool is_auto)
  104. {
  105. m_is_auto = is_auto;
  106. reset_automation();
  107. }
  108. void
  109. TextArrayObject::update(float dt_sec)
  110. {
  111. if (m_finished)
  112. return;
  113. // make sure there's anything to update
  114. if (m_texts.size() == 0)
  115. return;
  116. // detect change request
  117. handle_input_requests();
  118. // check if if should update auto narration
  119. if (m_is_auto && m_waiting.check()) {
  120. next_text();
  121. }
  122. // update current
  123. auto* curTextItem = get_current_text_item();
  124. if (curTextItem)
  125. curTextItem->text_object.update(dt_sec);
  126. // update last (if transition is enabled)
  127. if (should_fade()) {
  128. auto* lastTextItem = get_last_text_item();
  129. if (lastTextItem)
  130. lastTextItem->text_object.update(dt_sec);
  131. }
  132. }
  133. void
  134. TextArrayObject::draw(DrawingContext& context)
  135. {
  136. if (m_finished)
  137. return;
  138. auto* curTextItem = get_current_text_item();
  139. if (!curTextItem)
  140. return;
  141. // draw last if transition enabled
  142. if (should_fade()) {
  143. auto* lastTextItem = get_last_text_item();
  144. if (lastTextItem)
  145. lastTextItem->text_object.draw(context);
  146. }
  147. // draw current
  148. curTextItem->text_object.draw(context);
  149. }
  150. void
  151. TextArrayObject::override_properties()
  152. {
  153. if (!(should_fade() || m_keep_visible))
  154. return;
  155. auto* curTextItem = get_current_text_item();
  156. if (!curTextItem)
  157. return;
  158. // apply overrides
  159. if (should_fade()) { // make fade transition
  160. auto* lastTextItem = get_last_text_item();
  161. if (lastTextItem) {
  162. lastTextItem->text_object.fade_out(m_fadetime);
  163. curTextItem->text_object.fade_in(m_fadetime);
  164. }
  165. } else if (m_keep_visible) { // keep visible
  166. curTextItem->text_object.set_visible(true);
  167. }
  168. }
  169. void
  170. TextArrayObject::reset_automation()
  171. {
  172. m_waiting.stop();
  173. if (m_is_auto) {
  174. auto* text = get_current_text_item();
  175. if (text)
  176. m_waiting.start(text->duration);
  177. }
  178. }
  179. void
  180. TextArrayObject::handle_input_requests()
  181. {
  182. const Controller& controller = InputManager::current()->get_controller();
  183. if (controller.pressed(Control::MENU_SELECT)) {
  184. m_is_auto = false;
  185. next_text();
  186. } else if (controller.pressed(Control::REMOVE)) {
  187. m_is_auto = false;
  188. prev_text();
  189. }
  190. }
  191. bool
  192. TextArrayObject::should_fade() const
  193. {
  194. return m_fade_transition && (m_curTextIndex != m_lastTextIndex);
  195. }
  196. /** TextObject functions */
  197. #define TEXT_OBJECT_FUNCTION_VOID(F) \
  198. TextArrayItem* item = get_current_text_item(); \
  199. if (item) { \
  200. item->text_object.F; \
  201. return; \
  202. }
  203. #define TEXT_OBJECT_FUNCTION_RETURN(F) \
  204. TextArrayItem* item = get_current_text_item(); \
  205. if (item) \
  206. return item->text_object.F;
  207. #define TEXT_OBJECT_FUNCTION_VOID_THROW(F) \
  208. TEXT_OBJECT_FUNCTION_VOID(F) \
  209. throw std::runtime_error("No current TextObject in TextArrayObject!");
  210. #define TEXT_OBJECT_FUNCTION_RETURN_THROW(F) \
  211. TEXT_OBJECT_FUNCTION_RETURN(F) \
  212. throw std::runtime_error("No current TextObject in TextArrayObject!");
  213. void
  214. TextArrayObject::set_text(const std::string& text)
  215. {
  216. TEXT_OBJECT_FUNCTION_VOID(set_text(text))
  217. add_text(text);
  218. }
  219. const std::string&
  220. TextArrayObject::get_text() const
  221. {
  222. TEXT_OBJECT_FUNCTION_RETURN_THROW(get_text())
  223. }
  224. void
  225. TextArrayObject::set_font(const std::string& fontname)
  226. {
  227. TEXT_OBJECT_FUNCTION_VOID_THROW(set_font(fontname))
  228. }
  229. void
  230. TextArrayObject::fade_in(float fadetime)
  231. {
  232. TEXT_OBJECT_FUNCTION_VOID_THROW(fade_in(fadetime))
  233. }
  234. void
  235. TextArrayObject::fade_out(float fadetime)
  236. {
  237. TEXT_OBJECT_FUNCTION_VOID_THROW(fade_out(fadetime))
  238. }
  239. void
  240. TextArrayObject::grow_in(float fadetime)
  241. {
  242. TEXT_OBJECT_FUNCTION_VOID_THROW(grow_in(fadetime))
  243. }
  244. void
  245. TextArrayObject::grow_out(float fadetime)
  246. {
  247. TEXT_OBJECT_FUNCTION_VOID_THROW(grow_out(fadetime))
  248. }
  249. void
  250. TextArrayObject::set_visible(bool visible)
  251. {
  252. TEXT_OBJECT_FUNCTION_VOID_THROW(set_visible(visible))
  253. }
  254. bool
  255. TextArrayObject::get_visible() const
  256. {
  257. TEXT_OBJECT_FUNCTION_RETURN_THROW(get_visible())
  258. }
  259. void
  260. TextArrayObject::set_centered(bool centered)
  261. {
  262. TEXT_OBJECT_FUNCTION_VOID_THROW(set_centered(centered))
  263. }
  264. bool
  265. TextArrayObject::get_centered() const
  266. {
  267. TEXT_OBJECT_FUNCTION_RETURN_THROW(get_centered())
  268. }
  269. void
  270. TextArrayObject::set_pos(float x, float y)
  271. {
  272. TEXT_OBJECT_FUNCTION_VOID_THROW(set_pos(Vector(x, y)))
  273. }
  274. float
  275. TextArrayObject::get_x() const
  276. {
  277. TEXT_OBJECT_FUNCTION_RETURN_THROW(get_pos().x)
  278. }
  279. float
  280. TextArrayObject::get_y() const
  281. {
  282. TEXT_OBJECT_FUNCTION_RETURN_THROW(get_pos().y)
  283. }
  284. void
  285. TextArrayObject::set_anchor_point(int anchor)
  286. {
  287. TEXT_OBJECT_FUNCTION_VOID_THROW(set_anchor_point(static_cast<AnchorPoint>(anchor)))
  288. }
  289. int
  290. TextArrayObject::get_anchor_point() const
  291. {
  292. TEXT_OBJECT_FUNCTION_RETURN_THROW(get_anchor_point())
  293. }
  294. void
  295. TextArrayObject::set_anchor_offset(float x, float y)
  296. {
  297. TEXT_OBJECT_FUNCTION_VOID_THROW(set_anchor_offset(x, y))
  298. }
  299. float
  300. TextArrayObject::get_wrap_width() const
  301. {
  302. TEXT_OBJECT_FUNCTION_RETURN_THROW(get_wrap_width())
  303. }
  304. void
  305. TextArrayObject::set_wrap_width(float width)
  306. {
  307. TEXT_OBJECT_FUNCTION_VOID_THROW(set_wrap_width(width))
  308. }
  309. void
  310. TextArrayObject::set_front_fill_color(float red, float green, float blue, float alpha)
  311. {
  312. TEXT_OBJECT_FUNCTION_VOID_THROW(set_front_fill_color(red, green, blue, alpha))
  313. }
  314. void
  315. TextArrayObject::set_back_fill_color(float red, float green, float blue, float alpha)
  316. {
  317. TEXT_OBJECT_FUNCTION_VOID_THROW(set_back_fill_color(red, green, blue, alpha))
  318. }
  319. void
  320. TextArrayObject::set_text_color(float red, float green, float blue, float alpha)
  321. {
  322. TEXT_OBJECT_FUNCTION_VOID_THROW(set_text_color(red, green, blue, alpha))
  323. }
  324. void
  325. TextArrayObject::set_roundness(float roundness)
  326. {
  327. TEXT_OBJECT_FUNCTION_VOID_THROW(set_roundness(roundness))
  328. }
  329. float
  330. TextArrayObject::get_roundness() const
  331. {
  332. TEXT_OBJECT_FUNCTION_RETURN_THROW(get_roundness())
  333. }
  334. #undef TEXT_OBJECT_FUNCTION_VOID
  335. #undef TEXT_OBJECT_FUNCTION_RETURN
  336. #undef TEXT_OBJECT_FUNCTION_VOID_THROW
  337. #undef TEXT_OBJECT_FUNCTION_RETURN_THROW
  338. void
  339. TextArrayObject::register_class(ssq::VM& vm)
  340. {
  341. ssq::Class cls = vm.addClass("TextArrayObject", []()
  342. {
  343. if (!Sector::current())
  344. throw std::runtime_error("Tried to create 'TextArrayObject' without an active sector.");
  345. return &Sector::get().add<TextArrayObject>();
  346. },
  347. {},
  348. false /* Do not free pointer from Squirrel */,
  349. vm.findClass("GameObject"));
  350. cls.addFunc("clear", &TextArrayObject::clear);
  351. cls.addFunc("add_text", &TextArrayObject::add_text);
  352. cls.addFunc("add_text_duration", &TextArrayObject::add_text_duration);
  353. cls.addFunc("set_text_index", &TextArrayObject::set_text_index);
  354. cls.addFunc("set_keep_visible", &TextArrayObject::set_keep_visible);
  355. cls.addFunc("set_fade_transition", &TextArrayObject::set_fade_transition);
  356. cls.addFunc("set_fade_time", &TextArrayObject::set_fade_time);
  357. cls.addFunc("set_done", &TextArrayObject::set_done);
  358. cls.addFunc("set_auto", &TextArrayObject::set_auto);
  359. cls.addFunc("next_text", &TextArrayObject::next_text);
  360. cls.addFunc("prev_text", &TextArrayObject::prev_text);
  361. cls.addVar("keep_visible", &TextArrayObject::m_keep_visible);
  362. cls.addVar("fade_transition", &TextArrayObject::m_fade_transition);
  363. cls.addVar("finished", &TextArrayObject::m_finished);
  364. /* TextObject API related */
  365. cls.addFunc("set_text", &TextArrayObject::set_text);
  366. cls.addFunc("get_text", &TextArrayObject::get_text);
  367. cls.addFunc("set_font", &TextArrayObject::set_font);
  368. cls.addFunc("fade_in", &TextArrayObject::fade_in);
  369. cls.addFunc("fade_out", &TextArrayObject::fade_out);
  370. cls.addFunc("grow_in", &TextArrayObject::grow_in);
  371. cls.addFunc("grow_out", &TextArrayObject::grow_out);
  372. cls.addFunc("set_visible", &TextArrayObject::set_visible);
  373. cls.addFunc("get_visible", &TextArrayObject::get_visible);
  374. cls.addFunc("set_centered", &TextArrayObject::set_centered);
  375. cls.addFunc("get_centered", &TextArrayObject::get_centered);
  376. cls.addFunc("set_pos", &TextArrayObject::set_pos);
  377. cls.addFunc("get_x", &TextArrayObject::get_x);
  378. cls.addFunc("get_y", &TextArrayObject::get_y);
  379. cls.addFunc("get_pos_x", &TextArrayObject::get_x); // Deprecated
  380. cls.addFunc("get_pos_y", &TextArrayObject::get_y); // Deprecated
  381. cls.addFunc("set_anchor_point", &TextArrayObject::set_anchor_point);
  382. cls.addFunc("get_anchor_point", &TextArrayObject::get_anchor_point);
  383. cls.addFunc("set_anchor_offset", &TextArrayObject::set_anchor_offset);
  384. cls.addFunc("get_wrap_width", &TextArrayObject::get_wrap_width);
  385. cls.addFunc("set_wrap_width", &TextArrayObject::set_wrap_width);
  386. cls.addFunc("set_front_fill_color", &TextArrayObject::set_front_fill_color);
  387. cls.addFunc("set_back_fill_color", &TextArrayObject::set_back_fill_color);
  388. cls.addFunc("set_text_color", &TextArrayObject::set_text_color);
  389. cls.addFunc("set_roundness", &TextArrayObject::set_roundness);
  390. cls.addFunc("get_roundness", &TextArrayObject::set_roundness);
  391. cls.addVar("text", &TextArrayObject::get_text, &TextArrayObject::set_text);
  392. cls.addVar("visible", &TextArrayObject::get_visible, &TextArrayObject::set_visible);
  393. cls.addVar("centered", &TextArrayObject::get_centered, &TextArrayObject::set_centered);
  394. cls.addVar("anchor_point", &TextArrayObject::get_anchor_point, &TextArrayObject::set_anchor_point);
  395. cls.addVar("wrap_width", &TextArrayObject::get_wrap_width, &TextArrayObject::set_wrap_width);
  396. cls.addVar("roundness", &TextArrayObject::get_roundness, &TextArrayObject::set_roundness);
  397. }
  398. /* EOF */