PageRenderTime 43ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/llui/lltimectrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 432 lines | 329 code | 65 blank | 38 comment | 41 complexity | eb24a6e55a7476a6f81e1b8a59a2073a MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lltimectrl.cpp
  3. * @brief LLTimeCtrl base class
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2011, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "lltimectrl.h"
  28. #include "llui.h"
  29. #include "lluiconstants.h"
  30. #include "llbutton.h"
  31. #include "llfontgl.h"
  32. #include "lllineeditor.h"
  33. #include "llkeyboard.h"
  34. #include "llstring.h"
  35. #include "lltextbox.h"
  36. #include "lluictrlfactory.h"
  37. static LLDefaultChildRegistry::Register<LLTimeCtrl> time_r("time");
  38. const U32 AMPM_LEN = 3;
  39. const U32 MINUTES_MIN = 0;
  40. const U32 MINUTES_MAX = 59;
  41. const U32 HOURS_MIN = 1;
  42. const U32 HOURS_MAX = 12;
  43. const U32 MINUTES_PER_HOUR = 60;
  44. const U32 MINUTES_PER_DAY = 24 * MINUTES_PER_HOUR;
  45. LLTimeCtrl::Params::Params()
  46. : label_width("label_width"),
  47. snap_to("snap_to"),
  48. allow_text_entry("allow_text_entry", true),
  49. text_enabled_color("text_enabled_color"),
  50. text_disabled_color("text_disabled_color"),
  51. up_button("up_button"),
  52. down_button("down_button")
  53. {}
  54. LLTimeCtrl::LLTimeCtrl(const LLTimeCtrl::Params& p)
  55. : LLUICtrl(p),
  56. mLabelBox(NULL),
  57. mTextEnabledColor(p.text_enabled_color()),
  58. mTextDisabledColor(p.text_disabled_color()),
  59. mTime(0),
  60. mSnapToMin(5)
  61. {
  62. static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0);
  63. static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0);
  64. static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0);
  65. S32 centered_top = getRect().getHeight();
  66. S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height;
  67. S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40));
  68. S32 editor_left = label_width + spinctrl_spacing;
  69. //================= Label =================//
  70. if( !p.label().empty() )
  71. {
  72. LLRect label_rect( 0, centered_top, label_width, centered_bottom );
  73. LLTextBox::Params params;
  74. params.name("TimeCtrl Label");
  75. params.rect(label_rect);
  76. params.initial_value(p.label());
  77. if (p.font.isProvided())
  78. {
  79. params.font(p.font);
  80. }
  81. mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
  82. addChild(mLabelBox);
  83. editor_left = label_rect.mRight + spinctrl_spacing;
  84. }
  85. S32 editor_right = getRect().getWidth() - spinctrl_btn_width - spinctrl_spacing;
  86. //================= Editor ================//
  87. LLRect editor_rect( editor_left, centered_top, editor_right, centered_bottom );
  88. LLLineEditor::Params params;
  89. params.name("SpinCtrl Editor");
  90. params.rect(editor_rect);
  91. if (p.font.isProvided())
  92. {
  93. params.font(p.font);
  94. }
  95. params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
  96. params.max_length.chars(8);
  97. params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1));
  98. mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
  99. mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace);
  100. mEditor->setPrevalidate(boost::bind(&LLTimeCtrl::isTimeStringValid, this, _1));
  101. mEditor->setText(LLStringExplicit("12:00 AM"));
  102. addChild(mEditor);
  103. //================= Spin Buttons ==========//
  104. LLButton::Params up_button_params(p.up_button);
  105. up_button_params.rect = LLRect(editor_right + 1, getRect().getHeight(), editor_right + spinctrl_btn_width, getRect().getHeight() - spinctrl_btn_height);
  106. up_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this));
  107. up_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this));
  108. mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
  109. addChild(mUpBtn);
  110. LLButton::Params down_button_params(p.down_button);
  111. down_button_params.rect = LLRect(editor_right + 1, getRect().getHeight() - spinctrl_btn_height, editor_right + spinctrl_btn_width, getRect().getHeight() - 2 * spinctrl_btn_height);
  112. down_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this));
  113. down_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this));
  114. mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
  115. addChild(mDownBtn);
  116. setUseBoundingRect( TRUE );
  117. }
  118. F32 LLTimeCtrl::getTime24() const
  119. {
  120. // 0.0 - 23.99;
  121. return mTime / 60.0f;
  122. }
  123. U32 LLTimeCtrl::getHours24() const
  124. {
  125. return (U32) getTime24();
  126. }
  127. U32 LLTimeCtrl::getMinutes() const
  128. {
  129. return mTime % MINUTES_PER_HOUR;
  130. }
  131. void LLTimeCtrl::setTime24(F32 time)
  132. {
  133. time = llclamp(time, 0.0f, 23.99f); // fix out of range values
  134. mTime = llround(time * MINUTES_PER_HOUR); // fixes values like 4.99999
  135. updateText();
  136. }
  137. BOOL LLTimeCtrl::handleKeyHere(KEY key, MASK mask)
  138. {
  139. if (mEditor->hasFocus())
  140. {
  141. if(key == KEY_UP)
  142. {
  143. onUpBtn();
  144. return TRUE;
  145. }
  146. if(key == KEY_DOWN)
  147. {
  148. onDownBtn();
  149. return TRUE;
  150. }
  151. if (key == KEY_RETURN)
  152. {
  153. onCommit();
  154. return TRUE;
  155. }
  156. }
  157. return FALSE;
  158. }
  159. void LLTimeCtrl::onUpBtn()
  160. {
  161. switch(getEditingPart())
  162. {
  163. case HOURS:
  164. increaseHours();
  165. break;
  166. case MINUTES:
  167. increaseMinutes();
  168. break;
  169. case DAYPART:
  170. switchDayPeriod();
  171. break;
  172. default:
  173. break;
  174. }
  175. updateText();
  176. onCommit();
  177. }
  178. void LLTimeCtrl::onDownBtn()
  179. {
  180. switch(getEditingPart())
  181. {
  182. case HOURS:
  183. decreaseHours();
  184. break;
  185. case MINUTES:
  186. decreaseMinutes();
  187. break;
  188. case DAYPART:
  189. switchDayPeriod();
  190. break;
  191. default:
  192. break;
  193. }
  194. updateText();
  195. onCommit();
  196. }
  197. void LLTimeCtrl::onFocusLost()
  198. {
  199. updateText();
  200. onCommit();
  201. LLUICtrl::onFocusLost();
  202. }
  203. void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor)
  204. {
  205. std::string time_str = line_editor->getText();
  206. U32 h12 = parseHours(getHoursString(time_str));
  207. U32 m = parseMinutes(getMinutesString(time_str));
  208. bool pm = parseAMPM(getAMPMString(time_str));
  209. if (h12 == 12)
  210. {
  211. h12 = 0;
  212. }
  213. U32 h24 = pm ? h12 + 12 : h12;
  214. mTime = h24 * MINUTES_PER_HOUR + m;
  215. }
  216. bool LLTimeCtrl::isTimeStringValid(const LLWString &wstr)
  217. {
  218. std::string str = wstring_to_utf8str(wstr);
  219. return isHoursStringValid(getHoursString(str)) &&
  220. isMinutesStringValid(getMinutesString(str)) &&
  221. isPMAMStringValid(getAMPMString(str));
  222. }
  223. void LLTimeCtrl::increaseMinutes()
  224. {
  225. mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin);
  226. }
  227. void LLTimeCtrl::increaseHours()
  228. {
  229. mTime = (mTime + MINUTES_PER_HOUR) % MINUTES_PER_DAY;
  230. }
  231. void LLTimeCtrl::decreaseMinutes()
  232. {
  233. if (mTime < mSnapToMin)
  234. {
  235. mTime = MINUTES_PER_DAY - mTime;
  236. }
  237. mTime -= (mTime % mSnapToMin) ? mTime % mSnapToMin : mSnapToMin;
  238. }
  239. void LLTimeCtrl::decreaseHours()
  240. {
  241. if (mTime < MINUTES_PER_HOUR)
  242. {
  243. mTime = 23 * MINUTES_PER_HOUR + mTime;
  244. }
  245. else
  246. {
  247. mTime -= MINUTES_PER_HOUR;
  248. }
  249. }
  250. bool LLTimeCtrl::isPM() const
  251. {
  252. return mTime >= (MINUTES_PER_DAY / 2);
  253. }
  254. void LLTimeCtrl::switchDayPeriod()
  255. {
  256. if (isPM())
  257. {
  258. mTime -= MINUTES_PER_DAY / 2;
  259. }
  260. else
  261. {
  262. mTime += MINUTES_PER_DAY / 2;
  263. }
  264. }
  265. void LLTimeCtrl::updateText()
  266. {
  267. U32 h24 = getHours24();
  268. U32 m = getMinutes();
  269. U32 h12 = h24 > 12 ? h24 - 12 : h24;
  270. if (h12 == 0)
  271. h12 = 12;
  272. mEditor->setText(llformat("%d:%02d %s", h12, m, isPM() ? "PM":"AM"));
  273. }
  274. LLTimeCtrl::EEditingPart LLTimeCtrl::getEditingPart()
  275. {
  276. S32 cur_pos = mEditor->getCursor();
  277. std::string time_str = mEditor->getText();
  278. S32 colon_index = time_str.find_first_of(':');
  279. if (cur_pos <= colon_index)
  280. {
  281. return HOURS;
  282. }
  283. else if (cur_pos > colon_index && cur_pos <= (S32)(time_str.length() - AMPM_LEN))
  284. {
  285. return MINUTES;
  286. }
  287. else if (cur_pos > (S32)(time_str.length() - AMPM_LEN))
  288. {
  289. return DAYPART;
  290. }
  291. return NONE;
  292. }
  293. // static
  294. std::string LLTimeCtrl::getHoursString(const std::string& str)
  295. {
  296. size_t colon_index = str.find_first_of(':');
  297. std::string hours_str = str.substr(0, colon_index);
  298. return hours_str;
  299. }
  300. // static
  301. std::string LLTimeCtrl::getMinutesString(const std::string& str)
  302. {
  303. size_t colon_index = str.find_first_of(':');
  304. ++colon_index;
  305. int minutes_len = str.length() - colon_index - AMPM_LEN;
  306. std::string minutes_str = str.substr(colon_index, minutes_len);
  307. return minutes_str;
  308. }
  309. // static
  310. std::string LLTimeCtrl::getAMPMString(const std::string& str)
  311. {
  312. return str.substr(str.size() - 2, 2); // returns last two characters
  313. }
  314. // static
  315. bool LLTimeCtrl::isHoursStringValid(const std::string& str)
  316. {
  317. U32 hours;
  318. if ((!LLStringUtil::convertToU32(str, hours) || (hours <= HOURS_MAX)) && str.length() < 3)
  319. return true;
  320. return false;
  321. }
  322. // static
  323. bool LLTimeCtrl::isMinutesStringValid(const std::string& str)
  324. {
  325. U32 minutes;
  326. if (!LLStringUtil::convertToU32(str, minutes) || (minutes <= MINUTES_MAX) && str.length() < 3)
  327. return true;
  328. return false;
  329. }
  330. // static
  331. bool LLTimeCtrl::isPMAMStringValid(const std::string& str)
  332. {
  333. S32 len = str.length();
  334. bool valid = (str[--len] == 'M') && (str[--len] == 'P' || str[len] == 'A');
  335. return valid;
  336. }
  337. // static
  338. U32 LLTimeCtrl::parseHours(const std::string& str)
  339. {
  340. U32 hours;
  341. if (LLStringUtil::convertToU32(str, hours) && (hours >= HOURS_MIN) && (hours <= HOURS_MAX))
  342. {
  343. return hours;
  344. }
  345. else
  346. {
  347. return HOURS_MIN;
  348. }
  349. }
  350. // static
  351. U32 LLTimeCtrl::parseMinutes(const std::string& str)
  352. {
  353. U32 minutes;
  354. if (LLStringUtil::convertToU32(str, minutes) && (minutes >= MINUTES_MIN) && (minutes <= MINUTES_MAX))
  355. {
  356. return minutes;
  357. }
  358. else
  359. {
  360. return MINUTES_MIN;
  361. }
  362. }
  363. // static
  364. bool LLTimeCtrl::parseAMPM(const std::string& str)
  365. {
  366. return str == "PM";
  367. }