guiEditBoxWithScrollbar.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt
  2. // Modified by Mustapha T.
  3. // This file is part of the "Irrlicht Engine".
  4. // For conditions of distribution and use, see copyright notice in irrlicht.h
  5. #include "guiEditBoxWithScrollbar.h"
  6. #include "IGUISkin.h"
  7. #include "IGUIEnvironment.h"
  8. #include "IGUIFont.h"
  9. #include "IVideoDriver.h"
  10. #include "rect.h"
  11. #include "porting.h"
  12. #include "Keycodes.h"
  13. /*
  14. todo:
  15. optional scrollbars [done]
  16. ctrl+left/right to select word
  17. double click/ctrl click: word select + drag to select whole words, triple click to select line
  18. optional? dragging selected text
  19. numerical
  20. */
  21. //! constructor
  22. GUIEditBoxWithScrollBar::GUIEditBoxWithScrollBar(const wchar_t* text, bool border,
  23. IGUIEnvironment* environment, IGUIElement* parent, s32 id,
  24. const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar)
  25. : GUIEditBox(environment, parent, id, rectangle, border, writable),
  26. m_background(true), m_bg_color_used(false)
  27. {
  28. #ifdef _DEBUG
  29. setDebugName("GUIEditBoxWithScrollBar");
  30. #endif
  31. Text = text;
  32. if (Environment)
  33. m_operator = Environment->getOSOperator();
  34. if (m_operator)
  35. m_operator->grab();
  36. // this element can be tabbed to
  37. setTabStop(true);
  38. setTabOrder(-1);
  39. if (has_vscrollbar) {
  40. createVScrollBar();
  41. }
  42. calculateFrameRect();
  43. breakText();
  44. calculateScrollPos();
  45. setWritable(writable);
  46. }
  47. //! Sets whether to draw the background
  48. void GUIEditBoxWithScrollBar::setDrawBackground(bool draw)
  49. {
  50. m_background = draw;
  51. }
  52. void GUIEditBoxWithScrollBar::updateAbsolutePosition()
  53. {
  54. core::rect<s32> old_absolute_rect(AbsoluteRect);
  55. IGUIElement::updateAbsolutePosition();
  56. if (old_absolute_rect != AbsoluteRect) {
  57. calculateFrameRect();
  58. breakText();
  59. calculateScrollPos();
  60. }
  61. }
  62. //! draws the element and its children
  63. void GUIEditBoxWithScrollBar::draw()
  64. {
  65. if (!IsVisible)
  66. return;
  67. const bool focus = Environment->hasFocus(this);
  68. IGUISkin* skin = Environment->getSkin();
  69. if (!skin)
  70. return;
  71. video::SColor default_bg_color;
  72. video::SColor bg_color;
  73. default_bg_color = m_writable ? skin->getColor(EGDC_WINDOW) : video::SColor(0);
  74. bg_color = m_bg_color_used ? m_bg_color : default_bg_color;
  75. if (!m_border && m_background) {
  76. skin->draw2DRectangle(this, bg_color, AbsoluteRect, &AbsoluteClippingRect);
  77. }
  78. // draw the border
  79. if (m_border) {
  80. if (m_writable) {
  81. skin->draw3DSunkenPane(this, bg_color, false, m_background,
  82. AbsoluteRect, &AbsoluteClippingRect);
  83. }
  84. calculateFrameRect();
  85. }
  86. core::rect<s32> local_clip_rect = m_frame_rect;
  87. local_clip_rect.clipAgainst(AbsoluteClippingRect);
  88. // draw the text
  89. IGUIFont* font = getActiveFont();
  90. s32 cursor_line = 0;
  91. s32 charcursorpos = 0;
  92. if (font) {
  93. if (m_last_break_font != font) {
  94. breakText();
  95. }
  96. // calculate cursor pos
  97. core::stringw *txt_line = &Text;
  98. s32 start_pos = 0;
  99. core::stringw s, s2;
  100. // get mark position
  101. const bool ml = (!m_passwordbox && (m_word_wrap || m_multiline));
  102. const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
  103. const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
  104. const s32 hline_start = ml ? getLineFromPos(realmbgn) : 0;
  105. const s32 hline_count = ml ? getLineFromPos(realmend) - hline_start + 1 : 1;
  106. const s32 line_count = ml ? m_broken_text.size() : 1;
  107. // Save the override color information.
  108. // Then, alter it if the edit box is disabled.
  109. const bool prevOver = m_override_color_enabled;
  110. const video::SColor prevColor = m_override_color;
  111. if (Text.size()) {
  112. if (!isEnabled() && !m_override_color_enabled) {
  113. m_override_color_enabled = true;
  114. m_override_color = skin->getColor(EGDC_GRAY_TEXT);
  115. }
  116. for (s32 i = 0; i < line_count; ++i) {
  117. setTextRect(i);
  118. // clipping test - don't draw anything outside the visible area
  119. core::rect<s32> c = local_clip_rect;
  120. c.clipAgainst(m_current_text_rect);
  121. if (!c.isValid())
  122. continue;
  123. // get current line
  124. if (m_passwordbox) {
  125. if (m_broken_text.size() != 1) {
  126. m_broken_text.clear();
  127. m_broken_text.emplace_back();
  128. }
  129. if (m_broken_text[0].size() != Text.size()){
  130. m_broken_text[0] = Text;
  131. for (u32 q = 0; q < Text.size(); ++q)
  132. {
  133. m_broken_text[0][q] = m_passwordchar;
  134. }
  135. }
  136. txt_line = &m_broken_text[0];
  137. start_pos = 0;
  138. } else {
  139. txt_line = ml ? &m_broken_text[i] : &Text;
  140. start_pos = ml ? m_broken_text_positions[i] : 0;
  141. }
  142. // draw normal text
  143. font->draw(txt_line->c_str(), m_current_text_rect,
  144. m_override_color_enabled ? m_override_color : skin->getColor(EGDC_BUTTON_TEXT),
  145. false, true, &local_clip_rect);
  146. // draw mark and marked text
  147. if (focus && m_mark_begin != m_mark_end && i >= hline_start && i < hline_start + hline_count) {
  148. s32 mbegin = 0, mend = 0;
  149. s32 lineStartPos = 0, lineEndPos = txt_line->size();
  150. if (i == hline_start) {
  151. // highlight start is on this line
  152. s = txt_line->subString(0, realmbgn - start_pos);
  153. mbegin = font->getDimension(s.c_str()).Width;
  154. // deal with kerning
  155. mbegin += font->getKerningWidth(
  156. &((*txt_line)[realmbgn - start_pos]),
  157. realmbgn - start_pos > 0 ? &((*txt_line)[realmbgn - start_pos - 1]) : 0);
  158. lineStartPos = realmbgn - start_pos;
  159. }
  160. if (i == hline_start + hline_count - 1) {
  161. // highlight end is on this line
  162. s2 = txt_line->subString(0, realmend - start_pos);
  163. mend = font->getDimension(s2.c_str()).Width;
  164. lineEndPos = (s32)s2.size();
  165. } else {
  166. mend = font->getDimension(txt_line->c_str()).Width;
  167. }
  168. m_current_text_rect.UpperLeftCorner.X += mbegin;
  169. m_current_text_rect.LowerRightCorner.X = m_current_text_rect.UpperLeftCorner.X + mend - mbegin;
  170. // draw mark
  171. skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), m_current_text_rect, &local_clip_rect);
  172. // draw marked text
  173. s = txt_line->subString(lineStartPos, lineEndPos - lineStartPos);
  174. if (s.size())
  175. font->draw(s.c_str(), m_current_text_rect,
  176. m_override_color_enabled ? m_override_color : skin->getColor(EGDC_HIGH_LIGHT_TEXT),
  177. false, true, &local_clip_rect);
  178. }
  179. }
  180. // Return the override color information to its previous settings.
  181. m_override_color_enabled = prevOver;
  182. m_override_color = prevColor;
  183. }
  184. // draw cursor
  185. if (IsEnabled && m_writable) {
  186. if (m_word_wrap || m_multiline) {
  187. cursor_line = getLineFromPos(m_cursor_pos);
  188. txt_line = &m_broken_text[cursor_line];
  189. start_pos = m_broken_text_positions[cursor_line];
  190. }
  191. s = txt_line->subString(0, m_cursor_pos - start_pos);
  192. charcursorpos = font->getDimension(s.c_str()).Width +
  193. font->getKerningWidth(L"_", m_cursor_pos - start_pos > 0 ? &((*txt_line)[m_cursor_pos - start_pos - 1]) : 0);
  194. if (focus && (porting::getTimeMs() - m_blink_start_time) % 700 < 350) {
  195. setTextRect(cursor_line);
  196. m_current_text_rect.UpperLeftCorner.X += charcursorpos;
  197. font->draw(L"_", m_current_text_rect,
  198. m_override_color_enabled ? m_override_color : skin->getColor(EGDC_BUTTON_TEXT),
  199. false, true, &local_clip_rect);
  200. }
  201. }
  202. }
  203. // draw children
  204. IGUIElement::draw();
  205. }
  206. s32 GUIEditBoxWithScrollBar::getCursorPos(s32 x, s32 y)
  207. {
  208. IGUIFont* font = getActiveFont();
  209. const u32 line_count = (m_word_wrap || m_multiline) ? m_broken_text.size() : 1;
  210. core::stringw *txt_line = 0;
  211. s32 start_pos = 0;
  212. x += 3;
  213. for (u32 i = 0; i < line_count; ++i) {
  214. setTextRect(i);
  215. if (i == 0 && y < m_current_text_rect.UpperLeftCorner.Y)
  216. y = m_current_text_rect.UpperLeftCorner.Y;
  217. if (i == line_count - 1 && y > m_current_text_rect.LowerRightCorner.Y)
  218. y = m_current_text_rect.LowerRightCorner.Y;
  219. // is it inside this region?
  220. if (y >= m_current_text_rect.UpperLeftCorner.Y && y <= m_current_text_rect.LowerRightCorner.Y) {
  221. // we've found the clicked line
  222. txt_line = (m_word_wrap || m_multiline) ? &m_broken_text[i] : &Text;
  223. start_pos = (m_word_wrap || m_multiline) ? m_broken_text_positions[i] : 0;
  224. break;
  225. }
  226. }
  227. if (x < m_current_text_rect.UpperLeftCorner.X)
  228. x = m_current_text_rect.UpperLeftCorner.X;
  229. if (!txt_line)
  230. return 0;
  231. s32 idx = font->getCharacterFromPos(txt_line->c_str(), x - m_current_text_rect.UpperLeftCorner.X);
  232. // click was on or left of the line
  233. if (idx != -1)
  234. return idx + start_pos;
  235. // click was off the right edge of the line, go to end.
  236. return txt_line->size() + start_pos;
  237. }
  238. //! Breaks the single text line.
  239. void GUIEditBoxWithScrollBar::breakText()
  240. {
  241. if ((!m_word_wrap && !m_multiline))
  242. return;
  243. m_broken_text.clear(); // need to reallocate :/
  244. m_broken_text_positions.clear();
  245. IGUIFont* font = getActiveFont();
  246. if (!font)
  247. return;
  248. m_last_break_font = font;
  249. core::stringw line;
  250. core::stringw word;
  251. core::stringw whitespace;
  252. s32 last_line_start = 0;
  253. s32 size = Text.size();
  254. s32 length = 0;
  255. s32 el_width = RelativeRect.getWidth() - m_scrollbar_width - 10;
  256. wchar_t c;
  257. for (s32 i = 0; i < size; ++i) {
  258. c = Text[i];
  259. bool line_break = false;
  260. if (c == L'\r') { // Mac or Windows breaks
  261. line_break = true;
  262. c = 0;
  263. if (Text[i + 1] == L'\n') { // Windows breaks
  264. // TODO: I (Michael) think that we shouldn't change the text given by the user for whatever reason.
  265. // Instead rework the cursor positioning to be able to handle this (but not in stable release
  266. // branch as users might already expect this behavior).
  267. Text.erase(i + 1);
  268. --size;
  269. if (m_cursor_pos > i)
  270. --m_cursor_pos;
  271. }
  272. } else if (c == L'\n') { // Unix breaks
  273. line_break = true;
  274. c = 0;
  275. }
  276. // don't break if we're not a multi-line edit box
  277. if (!m_multiline)
  278. line_break = false;
  279. if (c == L' ' || c == 0 || i == (size - 1)) {
  280. // here comes the next whitespace, look if
  281. // we can break the last word to the next line
  282. // We also break whitespace, otherwise cursor would vanish beside the right border.
  283. s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
  284. s32 worldlgth = font->getDimension(word.c_str()).Width;
  285. if (m_word_wrap && length + worldlgth + whitelgth > el_width && line.size() > 0) {
  286. // break to next line
  287. length = worldlgth;
  288. m_broken_text.push_back(line);
  289. m_broken_text_positions.push_back(last_line_start);
  290. last_line_start = i - (s32)word.size();
  291. line = word;
  292. } else {
  293. // add word to line
  294. line += whitespace;
  295. line += word;
  296. length += whitelgth + worldlgth;
  297. }
  298. word = L"";
  299. whitespace = L"";
  300. if (c)
  301. whitespace += c;
  302. // compute line break
  303. if (line_break) {
  304. line += whitespace;
  305. line += word;
  306. m_broken_text.push_back(line);
  307. m_broken_text_positions.push_back(last_line_start);
  308. last_line_start = i + 1;
  309. line = L"";
  310. word = L"";
  311. whitespace = L"";
  312. length = 0;
  313. }
  314. } else {
  315. // yippee this is a word..
  316. word += c;
  317. }
  318. }
  319. line += whitespace;
  320. line += word;
  321. m_broken_text.push_back(line);
  322. m_broken_text_positions.push_back(last_line_start);
  323. }
  324. // TODO: that function does interpret VAlign according to line-index (indexed
  325. // line is placed on top-center-bottom) but HAlign according to line-width
  326. // (pixels) and not by row.
  327. // Intuitively I suppose HAlign handling is better as VScrollPos should handle
  328. // the line-scrolling.
  329. // But please no one change this without also rewriting (and this time
  330. // testing!!!) autoscrolling (I noticed this when fixing the old autoscrolling).
  331. void GUIEditBoxWithScrollBar::setTextRect(s32 line)
  332. {
  333. if (line < 0)
  334. return;
  335. IGUIFont* font = getActiveFont();
  336. if (!font)
  337. return;
  338. core::dimension2du d;
  339. // get text dimension
  340. const u32 line_count = (m_word_wrap || m_multiline) ? m_broken_text.size() : 1;
  341. if (m_word_wrap || m_multiline) {
  342. d = font->getDimension(m_broken_text[line].c_str());
  343. } else {
  344. d = font->getDimension(Text.c_str());
  345. d.Height = AbsoluteRect.getHeight();
  346. }
  347. d.Height += font->getKerningHeight();
  348. // justification
  349. switch (m_halign) {
  350. case EGUIA_CENTER:
  351. // align to h centre
  352. m_current_text_rect.UpperLeftCorner.X = (m_frame_rect.getWidth() / 2) - (d.Width / 2);
  353. m_current_text_rect.LowerRightCorner.X = (m_frame_rect.getWidth() / 2) + (d.Width / 2);
  354. break;
  355. case EGUIA_LOWERRIGHT:
  356. // align to right edge
  357. m_current_text_rect.UpperLeftCorner.X = m_frame_rect.getWidth() - d.Width;
  358. m_current_text_rect.LowerRightCorner.X = m_frame_rect.getWidth();
  359. break;
  360. default:
  361. // align to left edge
  362. m_current_text_rect.UpperLeftCorner.X = 0;
  363. m_current_text_rect.LowerRightCorner.X = d.Width;
  364. }
  365. switch (m_valign) {
  366. case EGUIA_CENTER:
  367. // align to v centre
  368. m_current_text_rect.UpperLeftCorner.Y =
  369. (m_frame_rect.getHeight() / 2) - (line_count*d.Height) / 2 + d.Height*line;
  370. break;
  371. case EGUIA_LOWERRIGHT:
  372. // align to bottom edge
  373. m_current_text_rect.UpperLeftCorner.Y =
  374. m_frame_rect.getHeight() - line_count*d.Height + d.Height*line;
  375. break;
  376. default:
  377. // align to top edge
  378. m_current_text_rect.UpperLeftCorner.Y = d.Height*line;
  379. break;
  380. }
  381. m_current_text_rect.UpperLeftCorner.X -= m_hscroll_pos;
  382. m_current_text_rect.LowerRightCorner.X -= m_hscroll_pos;
  383. m_current_text_rect.UpperLeftCorner.Y -= m_vscroll_pos;
  384. m_current_text_rect.LowerRightCorner.Y = m_current_text_rect.UpperLeftCorner.Y + d.Height;
  385. m_current_text_rect += m_frame_rect.UpperLeftCorner;
  386. }
  387. // calculate autoscroll
  388. void GUIEditBoxWithScrollBar::calculateScrollPos()
  389. {
  390. if (!m_autoscroll)
  391. return;
  392. IGUISkin* skin = Environment->getSkin();
  393. if (!skin)
  394. return;
  395. IGUIFont* font = m_override_font ? m_override_font : skin->getFont();
  396. if (!font)
  397. return;
  398. s32 curs_line = getLineFromPos(m_cursor_pos);
  399. if (curs_line < 0)
  400. return;
  401. setTextRect(curs_line);
  402. const bool has_broken_text = m_multiline || m_word_wrap;
  403. // Check horizonal scrolling
  404. // NOTE: Calculations different to vertical scrolling because setTextRect interprets VAlign relative to line but HAlign not relative to row
  405. {
  406. // get cursor position
  407. IGUIFont* font = getActiveFont();
  408. if (!font)
  409. return;
  410. // get cursor area
  411. irr::u32 cursor_width = font->getDimension(L"_").Width;
  412. core::stringw *txt_line = has_broken_text ? &m_broken_text[curs_line] : &Text;
  413. s32 cpos = has_broken_text ? m_cursor_pos - m_broken_text_positions[curs_line] : m_cursor_pos; // column
  414. s32 cstart = font->getDimension(txt_line->subString(0, cpos).c_str()).Width; // pixels from text-start
  415. s32 cend = cstart + cursor_width;
  416. s32 txt_width = font->getDimension(txt_line->c_str()).Width;
  417. if (txt_width < m_frame_rect.getWidth()) {
  418. // TODO: Needs a clean left and right gap removal depending on HAlign, similar to vertical scrolling tests for top/bottom.
  419. // This check just fixes the case where it was most noticable (text smaller than clipping area).
  420. m_hscroll_pos = 0;
  421. setTextRect(curs_line);
  422. }
  423. if (m_current_text_rect.UpperLeftCorner.X + cstart < m_frame_rect.UpperLeftCorner.X) {
  424. // cursor to the left of the clipping area
  425. m_hscroll_pos -= m_frame_rect.UpperLeftCorner.X - (m_current_text_rect.UpperLeftCorner.X + cstart);
  426. setTextRect(curs_line);
  427. // TODO: should show more characters to the left when we're scrolling left
  428. // and the cursor reaches the border.
  429. } else if (m_current_text_rect.UpperLeftCorner.X + cend > m_frame_rect.LowerRightCorner.X) {
  430. // cursor to the right of the clipping area
  431. m_hscroll_pos += (m_current_text_rect.UpperLeftCorner.X + cend) - m_frame_rect.LowerRightCorner.X;
  432. setTextRect(curs_line);
  433. }
  434. }
  435. // calculate vertical scrolling
  436. if (has_broken_text) {
  437. irr::u32 line_height = font->getDimension(L"A").Height + font->getKerningHeight();
  438. // only up to 1 line fits?
  439. if (line_height >= (irr::u32)m_frame_rect.getHeight()) {
  440. m_vscroll_pos = 0;
  441. setTextRect(curs_line);
  442. s32 unscrolledPos = m_current_text_rect.UpperLeftCorner.Y;
  443. s32 pivot = m_frame_rect.UpperLeftCorner.Y;
  444. switch (m_valign) {
  445. case EGUIA_CENTER:
  446. pivot += m_frame_rect.getHeight() / 2;
  447. unscrolledPos += line_height / 2;
  448. break;
  449. case EGUIA_LOWERRIGHT:
  450. pivot += m_frame_rect.getHeight();
  451. unscrolledPos += line_height;
  452. break;
  453. default:
  454. break;
  455. }
  456. m_vscroll_pos = unscrolledPos - pivot;
  457. setTextRect(curs_line);
  458. } else {
  459. // First 2 checks are necessary when people delete lines
  460. setTextRect(0);
  461. if (m_current_text_rect.UpperLeftCorner.Y > m_frame_rect.UpperLeftCorner.Y && m_valign != EGUIA_LOWERRIGHT) {
  462. // first line is leaving a gap on top
  463. m_vscroll_pos = 0;
  464. } else if (m_valign != EGUIA_UPPERLEFT) {
  465. u32 lastLine = m_broken_text_positions.empty() ? 0 : m_broken_text_positions.size() - 1;
  466. setTextRect(lastLine);
  467. if (m_current_text_rect.LowerRightCorner.Y < m_frame_rect.LowerRightCorner.Y)
  468. {
  469. // last line is leaving a gap on bottom
  470. m_vscroll_pos -= m_frame_rect.LowerRightCorner.Y - m_current_text_rect.LowerRightCorner.Y;
  471. }
  472. }
  473. setTextRect(curs_line);
  474. if (m_current_text_rect.UpperLeftCorner.Y < m_frame_rect.UpperLeftCorner.Y) {
  475. // text above valid area
  476. m_vscroll_pos -= m_frame_rect.UpperLeftCorner.Y - m_current_text_rect.UpperLeftCorner.Y;
  477. setTextRect(curs_line);
  478. } else if (m_current_text_rect.LowerRightCorner.Y > m_frame_rect.LowerRightCorner.Y){
  479. // text below valid area
  480. m_vscroll_pos += m_current_text_rect.LowerRightCorner.Y - m_frame_rect.LowerRightCorner.Y;
  481. setTextRect(curs_line);
  482. }
  483. }
  484. }
  485. if (m_vscrollbar) {
  486. m_vscrollbar->setPos(m_vscroll_pos);
  487. }
  488. }
  489. void GUIEditBoxWithScrollBar::calculateFrameRect()
  490. {
  491. m_frame_rect = AbsoluteRect;
  492. IGUISkin *skin = 0;
  493. if (Environment)
  494. skin = Environment->getSkin();
  495. if (m_border && skin) {
  496. m_frame_rect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X) + 1;
  497. m_frame_rect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y) + 1;
  498. m_frame_rect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X) + 1;
  499. m_frame_rect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y) + 1;
  500. }
  501. updateVScrollBar();
  502. }
  503. //! create a vertical scroll bar
  504. void GUIEditBoxWithScrollBar::createVScrollBar()
  505. {
  506. IGUISkin *skin = 0;
  507. if (Environment)
  508. skin = Environment->getSkin();
  509. m_scrollbar_width = skin ? skin->getSize(gui::EGDS_SCROLLBAR_SIZE) : 16;
  510. irr::core::rect<s32> scrollbarrect = m_frame_rect;
  511. scrollbarrect.UpperLeftCorner.X += m_frame_rect.getWidth() - m_scrollbar_width;
  512. m_vscrollbar = new GUIScrollBar(Environment, getParent(), -1,
  513. scrollbarrect, false, true);
  514. m_vscrollbar->setVisible(false);
  515. m_vscrollbar->setSmallStep(1);
  516. m_vscrollbar->setLargeStep(1);
  517. }
  518. //! Change the background color
  519. void GUIEditBoxWithScrollBar::setBackgroundColor(const video::SColor &bg_color)
  520. {
  521. m_bg_color = bg_color;
  522. m_bg_color_used = true;
  523. }
  524. //! Writes attributes of the element.
  525. void GUIEditBoxWithScrollBar::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options = 0) const
  526. {
  527. out->addBool("Border", m_border);
  528. out->addBool("Background", m_background);
  529. // out->addFont("OverrideFont", OverrideFont);
  530. GUIEditBox::serializeAttributes(out, options);
  531. }
  532. //! Reads attributes of the element
  533. void GUIEditBoxWithScrollBar::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options = 0)
  534. {
  535. GUIEditBox::deserializeAttributes(in, options);
  536. setDrawBorder(in->getAttributeAsBool("Border"));
  537. setDrawBackground(in->getAttributeAsBool("Background"));
  538. }
  539. bool GUIEditBoxWithScrollBar::isDrawBackgroundEnabled() const { return false; }
  540. bool GUIEditBoxWithScrollBar::isDrawBorderEnabled() const { return false; }
  541. void GUIEditBoxWithScrollBar::setCursorChar(const wchar_t cursorChar) { }
  542. wchar_t GUIEditBoxWithScrollBar::getCursorChar() const { return '|'; }
  543. void GUIEditBoxWithScrollBar::setCursorBlinkTime(irr::u32 timeMs) { }
  544. irr::u32 GUIEditBoxWithScrollBar::getCursorBlinkTime() const { return 500; }