TextField.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. #include <sstream>
  2. #include "TextField.h"
  3. #include "Font.h"
  4. #include "DebugActor.h"
  5. #include "res/Resources.h"
  6. #include "RenderState.h"
  7. #include "utils/stringUtils.h"
  8. #include "core/gl/VideoDriverGLES20.h"
  9. #include "text_utils/TextBuilder.h"
  10. #include "text_utils/Node.h"
  11. #include "Serialize.h"
  12. #include "Material.h"
  13. namespace oxygine
  14. {
  15. TextField::TextField():
  16. _root(0),
  17. _textRect(0, 0, 0, 0)
  18. {
  19. _flags |= flag_rebuild;
  20. _style.font = NULL;
  21. if (DebugActor::resSystem)
  22. {
  23. if (ResFont* fnt = DebugActor::resSystem->getResFont("system"))
  24. {
  25. _style.font = fnt;
  26. }
  27. }
  28. }
  29. TextField::~TextField()
  30. {
  31. delete _root;
  32. _root = 0;
  33. }
  34. void TextField::copyFrom(const TextField& src, cloneOptions opt)
  35. {
  36. inherited::copyFrom(src, opt);
  37. _text = src._text;
  38. _style = src._style;
  39. _root = 0;
  40. _flags |= flag_rebuild;
  41. _textRect = src._textRect;
  42. }
  43. bool TextField::isOn(const Vector2& localPosition)
  44. {
  45. Rect r = getTextRect();
  46. r.expand(Point(_extendedIsOn, _extendedIsOn), Point(_extendedIsOn, _extendedIsOn));
  47. return r.pointIn(Point((int)localPosition.x, (int)localPosition.y));
  48. }
  49. void TextField::needRebuild()
  50. {
  51. _flags |= flag_rebuild;
  52. }
  53. void TextField::setVAlign(TextStyle::VerticalAlign align)
  54. {
  55. _style.vAlign = align;
  56. needRebuild();
  57. }
  58. void TextField::setMultiline(bool multiline)
  59. {
  60. _style.multiline = multiline;
  61. needRebuild();
  62. }
  63. void TextField::setBreakLongWords(bool val)
  64. {
  65. _style.breakLongWords = val;
  66. needRebuild();
  67. }
  68. void TextField::setLinesOffset(int offset)
  69. {
  70. _style.linesOffset = offset;
  71. needRebuild();
  72. }
  73. void TextField::setKerning(int kerning)
  74. {
  75. _style.kerning = kerning;
  76. needRebuild();
  77. }
  78. void TextField::setFontSize2Scale(int scale2size)
  79. {
  80. setFontSize(scale2size);
  81. }
  82. void TextField::setFontSize(int size)
  83. {
  84. _style.fontSize = size;
  85. needRebuild();
  86. }
  87. const ResFont* TextField::getFont() const
  88. {
  89. return _style.font;
  90. }
  91. void TextField::setFont(const ResFont* font)
  92. {
  93. _style.font = font;
  94. needRebuild();
  95. }
  96. void TextField::setOutlineColor(const Color& c)
  97. {
  98. _style.outlineColor = c;
  99. }
  100. void TextField::setOutline(float v)
  101. {
  102. _style.outline = v;
  103. }
  104. void TextField::setWeight(float v)
  105. {
  106. _style.weight = v;
  107. }
  108. void TextField::setHAlign(TextStyle::HorizontalAlign align)
  109. {
  110. _style.hAlign = align;
  111. needRebuild();
  112. }
  113. void TextField::setAlign(TextStyle::VerticalAlign vAlign, TextStyle::HorizontalAlign hAlign)
  114. {
  115. _style.vAlign = vAlign;
  116. _style.hAlign = hAlign;
  117. needRebuild();
  118. }
  119. void TextField::setStyle(const TextStyle& st)
  120. {
  121. TextStyle::HorizontalAlign halign = _style.hAlign;
  122. TextStyle::VerticalAlign valign = _style.vAlign;
  123. int size = _style.fontSize;
  124. _style = st;
  125. if (st.hAlign == TextStyle::HALIGN_DEFAULT)
  126. _style.hAlign = halign;
  127. if (st.vAlign == TextStyle::VALIGN_DEFAULT)
  128. _style.vAlign = valign;
  129. if (st.fontSize == 0)
  130. _style.fontSize = size;
  131. needRebuild();
  132. }
  133. void TextField::sizeChanged(const Vector2& size)
  134. {
  135. needRebuild();
  136. }
  137. void TextField::setText(const std::string& str)
  138. {
  139. _flags &= ~flag_html;
  140. if (_text != str)
  141. {
  142. _text = str;
  143. needRebuild();
  144. }
  145. }
  146. void TextField::setText(const std::wstring& str)
  147. {
  148. setText(ws2utf8(str.c_str()));
  149. }
  150. void TextField::setHtmlText(const std::string& str)
  151. {
  152. _flags |= flag_html;
  153. if (_text != str)
  154. {
  155. _text = str;
  156. needRebuild();
  157. }
  158. }
  159. void TextField::setHtmlText(const std::wstring& str)
  160. {
  161. setHtmlText(ws2utf8(str.c_str()));
  162. }
  163. int TextField::getFontSize2Scale() const
  164. {
  165. return _style.fontSize;
  166. }
  167. int TextField::getFontSize() const
  168. {
  169. return _style.fontSize;
  170. }
  171. int TextField::getLinesOffset() const
  172. {
  173. return _style.linesOffset;
  174. }
  175. TextStyle::VerticalAlign TextField::getVAlign() const
  176. {
  177. return _style.vAlign;
  178. }
  179. TextStyle::HorizontalAlign TextField::getHAlign() const
  180. {
  181. return _style.hAlign;
  182. }
  183. bool TextField::getMultiline() const
  184. {
  185. return _style.multiline;
  186. }
  187. bool TextField::getBreakLongWords() const
  188. {
  189. return _style.breakLongWords;
  190. }
  191. int TextField::getKerning() const
  192. {
  193. return _style.kerning;
  194. }
  195. const Color& TextField::getOutlineColor() const
  196. {
  197. return _style.outlineColor;
  198. }
  199. float TextField::getOutline() const
  200. {
  201. return _style.outline;
  202. }
  203. float TextField::getWeight() const
  204. {
  205. return _style.weight;
  206. }
  207. text::Symbol* TextField::getSymbolAt(int pos) const
  208. {
  209. return const_cast<TextField*>(this)->getRootNode()->getSymbol(pos);
  210. }
  211. const Rect& TextField::getTextRect() const
  212. {
  213. const_cast<TextField*>(this)->getRootNode();
  214. return _textRect;
  215. }
  216. bool TextField::getBounds(RectF& r) const
  217. {
  218. r = getTextRect().cast<RectF>();
  219. return true;
  220. }
  221. text::Node* TextField::getRootNode()
  222. {
  223. if ((_flags & flag_rebuild) && _style.font)
  224. {
  225. delete _root;
  226. _flags &= ~flag_rebuild;
  227. if (_flags & flag_html)
  228. {
  229. text::TextBuilder b;
  230. _root = b.parse(_text);
  231. }
  232. else
  233. {
  234. _root = new text::TextNode(_text.c_str());
  235. }
  236. text::Aligner rd(_style);
  237. rd.width = (int)getWidth();
  238. rd.height = (int)getHeight();
  239. rd.begin();
  240. _root->resize(rd);
  241. rd.end();
  242. _root->finalPass(rd);
  243. rd.bounds = (rd.bounds.cast<RectF>() / rd.getScale()).cast<Rect>();
  244. _textRect = rd.bounds;
  245. }
  246. return _root;
  247. }
  248. const char* get_valign(TextStyle::VerticalAlign v)
  249. {
  250. switch (v)
  251. {
  252. case TextStyle::VALIGN_BASELINE:
  253. return "baseline";
  254. case TextStyle::VALIGN_TOP:
  255. return "top";
  256. case TextStyle::VALIGN_BOTTOM:
  257. return "bottom";
  258. case TextStyle::VALIGN_MIDDLE:
  259. return "middle";
  260. }
  261. return "unknown";
  262. }
  263. const char* get_halign(TextStyle::HorizontalAlign v)
  264. {
  265. switch (v)
  266. {
  267. case TextStyle::HALIGN_DEFAULT:
  268. return "default";
  269. case TextStyle::HALIGN_LEFT:
  270. return "left";
  271. case TextStyle::HALIGN_RIGHT:
  272. return "right";
  273. case TextStyle::HALIGN_MIDDLE:
  274. return "middle";
  275. }
  276. return "unknown";
  277. }
  278. std::string dumpStyle(const TextStyle& s, bool onlydiff)
  279. {
  280. TextStyle def;
  281. std::stringstream stream;
  282. if (!onlydiff || def.hAlign != s.hAlign)
  283. stream << "hAlign=" << get_halign(s.hAlign);
  284. if (!onlydiff || def.vAlign != s.vAlign)
  285. stream << " vAlign=" << get_valign(s.vAlign);
  286. if (!onlydiff || def.multiline != s.multiline)
  287. stream << " " << (s.multiline ? "multiline" : "singleline");
  288. if (!onlydiff || def.breakLongWords != s.breakLongWords)
  289. stream << " " << (s.breakLongWords ? "breakLongWords=1" : "breakLongWords=0");
  290. if (!onlydiff || def.kerning != s.kerning)
  291. stream << " kerning=" << s.kerning;
  292. if (!onlydiff || def.linesOffset != s.linesOffset)
  293. stream << " linesOffset=" << s.linesOffset;
  294. if (!onlydiff || def.fontSize != s.fontSize)
  295. stream << " fontSize=" << s.fontSize;
  296. if (!onlydiff || def.outline != s.outline)
  297. stream << " outline=" << s.outline;
  298. if (s.font)
  299. {
  300. stream << " font='" << s.font->getName() << "'";
  301. }
  302. return stream.str();
  303. }
  304. std::string TextField::dump(const dumpOptions& options) const
  305. {
  306. std::stringstream stream;
  307. stream << "{TextField}\n";
  308. stream << _vstyle.dump();
  309. std::string text = _text;
  310. if (text.size() > 15)
  311. {
  312. text.resize(15);
  313. text += "...";
  314. }
  315. stream << " text=<div c='2b1a94'>'<![CDATA[" << text << "']]></div>";
  316. std::string st = dumpStyle(_style, true);
  317. if (st.size())
  318. stream << " textStyle={" << st << "}";
  319. if (_flags & flag_html)
  320. {
  321. stream << " htmlMode";
  322. }
  323. Rect r = const_cast<TextField*>(this)->getTextRect();
  324. stream << " textRect=(" << r.pos.x << ", " << r.pos.y << ", " << r.size.x << ", " << r.size.y << ")";
  325. stream << "\n" << Actor::dump(options);
  326. return stream.str();
  327. }
  328. void TextField::doRender(RenderState const& rs)
  329. {
  330. rs.material->doRender(this, rs);
  331. }
  332. void TextField::serialize(serializedata* data)
  333. {
  334. inherited::serialize(data);
  335. pugi::xml_node node = data->node;
  336. TextStyle def;
  337. if (!_text.empty())
  338. node.append_attribute("text").set_value(_text.c_str());
  339. setAttr(node, "fontsize2scale", _style.fontSize, def.fontSize);
  340. setAttr(node, "linesOffset", _style.linesOffset, def.linesOffset);
  341. setAttr(node, "kerning", _style.kerning, def.kerning);
  342. setAttr(node, "valign", _style.vAlign, def.vAlign);
  343. setAttr(node, "halign", _style.hAlign, def.hAlign);
  344. setAttr(node, "multiline", _style.multiline, def.multiline);
  345. setAttr(node, "breakLongWords", _style.breakLongWords, def.breakLongWords);
  346. if (_style.font)
  347. node.append_attribute("font").set_value(_style.font->getName().c_str());
  348. node.set_name("TextField");
  349. }
  350. void TextField::deserialize(const deserializedata* data)
  351. {
  352. inherited::deserialize(data);
  353. pugi::xml_node node = data->node;
  354. TextStyle def;
  355. _style.vAlign = (TextStyle::VerticalAlign)node.attribute("valign").as_int(def.vAlign);
  356. _style.hAlign = (TextStyle::HorizontalAlign)node.attribute("halign").as_int(def.hAlign);
  357. _style.multiline = node.attribute("multiline").as_bool(def.multiline);
  358. _style.breakLongWords = node.attribute("breakLongWords").as_bool(def.breakLongWords);
  359. _style.fontSize = node.attribute("fontsize2scale").as_int(def.fontSize);
  360. _style.linesOffset = node.attribute("linesOffset").as_int(def.linesOffset);
  361. _style.kerning = node.attribute("kerning").as_int(def.kerning);
  362. const char* fnt = node.attribute("font").as_string(0);
  363. if (fnt && *fnt)
  364. {
  365. ResFont* font = data->factory->getResFont(fnt);
  366. if (font)
  367. _style.font = font;
  368. }
  369. needRebuild();
  370. setText(node.attribute("text").as_string());
  371. }
  372. }