summaryrefslogtreecommitdiff
path: root/indra/llui/lltimectrl.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
committerAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
commit1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch)
treeab243607f74f78200787bba5b9b88f07ef1b966f /indra/llui/lltimectrl.cpp
parent6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff)
parente1623bb276f83a43ce7a197e388720c05bdefe61 (diff)
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts: # autobuild.xml # indra/cmake/CMakeLists.txt # indra/cmake/GoogleMock.cmake # indra/llaudio/llaudioengine_fmodstudio.cpp # indra/llaudio/llaudioengine_fmodstudio.h # indra/llaudio/lllistener_fmodstudio.cpp # indra/llaudio/lllistener_fmodstudio.h # indra/llaudio/llstreamingaudio_fmodstudio.cpp # indra/llaudio/llstreamingaudio_fmodstudio.h # indra/llcharacter/llmultigesture.cpp # indra/llcharacter/llmultigesture.h # indra/llimage/llimage.cpp # indra/llimage/llimagepng.cpp # indra/llimage/llimageworker.cpp # indra/llimage/tests/llimageworker_test.cpp # indra/llmessage/tests/llmockhttpclient.h # indra/llprimitive/llgltfmaterial.h # indra/llrender/llfontfreetype.cpp # indra/llui/llcombobox.cpp # indra/llui/llfolderview.cpp # indra/llui/llfolderviewmodel.h # indra/llui/lllineeditor.cpp # indra/llui/lllineeditor.h # indra/llui/lltextbase.cpp # indra/llui/lltextbase.h # indra/llui/lltexteditor.cpp # indra/llui/lltextvalidate.cpp # indra/llui/lltextvalidate.h # indra/llui/lluictrl.h # indra/llui/llview.cpp # indra/llwindow/llwindowmacosx.cpp # indra/newview/app_settings/settings.xml # indra/newview/llappearancemgr.cpp # indra/newview/llappearancemgr.h # indra/newview/llavatarpropertiesprocessor.cpp # indra/newview/llavatarpropertiesprocessor.h # indra/newview/llbreadcrumbview.cpp # indra/newview/llbreadcrumbview.h # indra/newview/llbreastmotion.cpp # indra/newview/llbreastmotion.h # indra/newview/llconversationmodel.h # indra/newview/lldensityctrl.cpp # indra/newview/lldensityctrl.h # indra/newview/llface.inl # indra/newview/llfloatereditsky.cpp # indra/newview/llfloatereditwater.cpp # indra/newview/llfloateremojipicker.h # indra/newview/llfloaterimsessiontab.cpp # indra/newview/llfloaterprofiletexture.cpp # indra/newview/llfloaterprofiletexture.h # indra/newview/llgesturemgr.cpp # indra/newview/llgesturemgr.h # indra/newview/llimpanel.cpp # indra/newview/llimpanel.h # indra/newview/llinventorybridge.cpp # indra/newview/llinventorybridge.h # indra/newview/llinventoryclipboard.cpp # indra/newview/llinventoryclipboard.h # indra/newview/llinventoryfunctions.cpp # indra/newview/llinventoryfunctions.h # indra/newview/llinventorygallery.cpp # indra/newview/lllistbrowser.cpp # indra/newview/lllistbrowser.h # indra/newview/llpanelobjectinventory.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llpanelprofile.h # indra/newview/llpreviewgesture.cpp # indra/newview/llsavedsettingsglue.cpp # indra/newview/llsavedsettingsglue.h # indra/newview/lltooldraganddrop.cpp # indra/newview/llurllineeditorctrl.cpp # indra/newview/llvectorperfoptions.cpp # indra/newview/llvectorperfoptions.h # indra/newview/llviewerparceloverlay.cpp # indra/newview/llviewertexlayer.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/macmain.h # indra/test/test.cpp
Diffstat (limited to 'indra/llui/lltimectrl.cpp')
-rw-r--r--indra/llui/lltimectrl.cpp887
1 files changed, 454 insertions, 433 deletions
diff --git a/indra/llui/lltimectrl.cpp b/indra/llui/lltimectrl.cpp
index 37cc52f967..5c298c9080 100644
--- a/indra/llui/lltimectrl.cpp
+++ b/indra/llui/lltimectrl.cpp
@@ -1,433 +1,454 @@
-/**
- * @file lltimectrl.cpp
- * @brief LLTimeCtrl base class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "lltimectrl.h"
-
-#include "llui.h"
-#include "lluiconstants.h"
-
-#include "llbutton.h"
-#include "llfontgl.h"
-#include "lllineeditor.h"
-#include "llkeyboard.h"
-#include "llstring.h"
-#include "lltextbox.h"
-#include "lluictrlfactory.h"
-
-static LLDefaultChildRegistry::Register<LLTimeCtrl> time_r("time");
-
-const U32 AMPM_LEN = 3;
-const U32 MINUTES_MIN = 0;
-const U32 MINUTES_MAX = 59;
-const U32 HOURS_MIN = 1;
-const U32 HOURS_MAX = 12;
-const U32 MINUTES_PER_HOUR = 60;
-const U32 MINUTES_PER_DAY = 24 * MINUTES_PER_HOUR;
-
-
-LLTimeCtrl::Params::Params()
-: label_width("label_width"),
- snap_to("snap_to"),
- allow_text_entry("allow_text_entry", true),
- text_enabled_color("text_enabled_color"),
- text_disabled_color("text_disabled_color"),
- up_button("up_button"),
- down_button("down_button")
-{}
-
-LLTimeCtrl::LLTimeCtrl(const LLTimeCtrl::Params& p)
-: LLUICtrl(p),
- mLabelBox(NULL),
- mTextEnabledColor(p.text_enabled_color()),
- mTextDisabledColor(p.text_disabled_color()),
- mTime(0),
- mSnapToMin(5)
-{
- static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0);
- static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0);
- static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0);
- S32 centered_top = getRect().getHeight();
- S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height;
- S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40));
- S32 editor_left = label_width + spinctrl_spacing;
-
- //================= Label =================//
- if( !p.label().empty() )
- {
- LLRect label_rect( 0, centered_top, label_width, centered_bottom );
- LLTextBox::Params params;
- params.name("TimeCtrl Label");
- params.rect(label_rect);
- params.initial_value(p.label());
- if (p.font.isProvided())
- {
- params.font(p.font);
- }
- mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
- addChild(mLabelBox);
-
- editor_left = label_rect.mRight + spinctrl_spacing;
- }
-
- S32 editor_right = getRect().getWidth() - spinctrl_btn_width - spinctrl_spacing;
-
- //================= Editor ================//
- LLRect editor_rect( editor_left, centered_top, editor_right, centered_bottom );
- LLLineEditor::Params params;
- params.name("SpinCtrl Editor");
- params.rect(editor_rect);
- if (p.font.isProvided())
- {
- params.font(p.font);
- }
-
- params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
- params.max_length.chars(8);
- params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1));
- mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
- mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace);
- mEditor->setPrevalidate(boost::bind(&LLTimeCtrl::isTimeStringValid, this, _1));
- mEditor->setText(LLStringExplicit("12:00 AM"));
- addChild(mEditor);
-
- //================= Spin Buttons ==========//
- LLButton::Params up_button_params(p.up_button);
- up_button_params.rect = LLRect(editor_right + 1, getRect().getHeight(), editor_right + spinctrl_btn_width, getRect().getHeight() - spinctrl_btn_height);
-
- up_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this));
- up_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this));
- mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
- addChild(mUpBtn);
-
- LLButton::Params down_button_params(p.down_button);
- down_button_params.rect = LLRect(editor_right + 1, getRect().getHeight() - spinctrl_btn_height, editor_right + spinctrl_btn_width, getRect().getHeight() - 2 * spinctrl_btn_height);
- down_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this));
- down_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this));
- mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
- addChild(mDownBtn);
-
- setUseBoundingRect( true );
-}
-
-F32 LLTimeCtrl::getTime24() const
-{
- // 0.0 - 23.99;
- return mTime / 60.0f;
-}
-
-U32 LLTimeCtrl::getHours24() const
-{
- return (U32) getTime24();
-}
-
-U32 LLTimeCtrl::getMinutes() const
-{
- return mTime % MINUTES_PER_HOUR;
-}
-
-void LLTimeCtrl::setTime24(F32 time)
-{
- time = llclamp(time, 0.0f, 23.99f); // fix out of range values
- mTime = ll_round(time * MINUTES_PER_HOUR); // fixes values like 4.99999
-
- updateText();
-}
-
-bool LLTimeCtrl::handleKeyHere(KEY key, MASK mask)
-{
- if (mEditor->hasFocus())
- {
- if(key == KEY_UP)
- {
- onUpBtn();
- return true;
- }
- if(key == KEY_DOWN)
- {
- onDownBtn();
- return true;
- }
- if (key == KEY_RETURN)
- {
- onCommit();
- return true;
- }
- }
- return false;
-}
-
-void LLTimeCtrl::onUpBtn()
-{
- switch(getEditingPart())
- {
- case HOURS:
- increaseHours();
- break;
- case MINUTES:
- increaseMinutes();
- break;
- case DAYPART:
- switchDayPeriod();
- break;
- default:
- break;
- }
-
- updateText();
- onCommit();
-}
-
-void LLTimeCtrl::onDownBtn()
-{
- switch(getEditingPart())
- {
- case HOURS:
- decreaseHours();
- break;
- case MINUTES:
- decreaseMinutes();
- break;
- case DAYPART:
- switchDayPeriod();
- break;
- default:
- break;
- }
-
- updateText();
- onCommit();
-}
-
-void LLTimeCtrl::onFocusLost()
-{
- updateText();
- onCommit();
- LLUICtrl::onFocusLost();
-}
-
-void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor)
-{
- std::string time_str = line_editor->getText();
- U32 h12 = parseHours(getHoursString(time_str));
- U32 m = parseMinutes(getMinutesString(time_str));
- bool pm = parseAMPM(getAMPMString(time_str));
-
- if (h12 == 12)
- {
- h12 = 0;
- }
-
- U32 h24 = pm ? h12 + 12 : h12;
-
- mTime = h24 * MINUTES_PER_HOUR + m;
-}
-
-bool LLTimeCtrl::isTimeStringValid(const LLWString &wstr)
-{
- std::string str = wstring_to_utf8str(wstr);
-
- return isHoursStringValid(getHoursString(str)) &&
- isMinutesStringValid(getMinutesString(str)) &&
- isPMAMStringValid(getAMPMString(str));
-}
-
-void LLTimeCtrl::increaseMinutes()
-{
- mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin);
-}
-
-void LLTimeCtrl::increaseHours()
-{
- mTime = (mTime + MINUTES_PER_HOUR) % MINUTES_PER_DAY;
-}
-
-void LLTimeCtrl::decreaseMinutes()
-{
- if (mTime < mSnapToMin)
- {
- mTime = MINUTES_PER_DAY - mTime;
- }
-
- mTime -= (mTime % mSnapToMin) ? mTime % mSnapToMin : mSnapToMin;
-}
-
-void LLTimeCtrl::decreaseHours()
-{
- if (mTime < MINUTES_PER_HOUR)
- {
- mTime = 23 * MINUTES_PER_HOUR + mTime;
- }
- else
- {
- mTime -= MINUTES_PER_HOUR;
- }
-}
-
-bool LLTimeCtrl::isPM() const
-{
- return mTime >= (MINUTES_PER_DAY / 2);
-}
-
-void LLTimeCtrl::switchDayPeriod()
-{
- if (isPM())
- {
- mTime -= MINUTES_PER_DAY / 2;
- }
- else
- {
- mTime += MINUTES_PER_DAY / 2;
- }
-}
-
-void LLTimeCtrl::updateText()
-{
- U32 h24 = getHours24();
- U32 m = getMinutes();
- U32 h12 = h24 > 12 ? h24 - 12 : h24;
-
- if (h12 == 0)
- h12 = 12;
-
- mEditor->setText(llformat("%d:%02d %s", h12, m, isPM() ? "PM":"AM"));
-}
-
-LLTimeCtrl::EEditingPart LLTimeCtrl::getEditingPart()
-{
- S32 cur_pos = mEditor->getCursor();
- std::string time_str = mEditor->getText();
-
- S32 colon_index = time_str.find_first_of(':');
-
- if (cur_pos <= colon_index)
- {
- return HOURS;
- }
- else if (cur_pos > colon_index && cur_pos <= (S32)(time_str.length() - AMPM_LEN))
- {
- return MINUTES;
- }
- else if (cur_pos > (S32)(time_str.length() - AMPM_LEN))
- {
- return DAYPART;
- }
-
- return NONE;
-}
-
-// static
-std::string LLTimeCtrl::getHoursString(const std::string& str)
-{
- size_t colon_index = str.find_first_of(':');
- std::string hours_str = str.substr(0, colon_index);
-
- return hours_str;
-}
-
-// static
-std::string LLTimeCtrl::getMinutesString(const std::string& str)
-{
- size_t colon_index = str.find_first_of(':');
- ++colon_index;
-
- int minutes_len = str.length() - colon_index - AMPM_LEN;
- std::string minutes_str = str.substr(colon_index, minutes_len);
-
- return minutes_str;
-}
-
-// static
-std::string LLTimeCtrl::getAMPMString(const std::string& str)
-{
- return str.substr(str.size() - 2, 2); // returns last two characters
-}
-
-// static
-bool LLTimeCtrl::isHoursStringValid(const std::string& str)
-{
- U32 hours;
- if ((!LLStringUtil::convertToU32(str, hours) || (hours <= HOURS_MAX)) && str.length() < 3)
- return true;
-
- return false;
-}
-
-// static
-bool LLTimeCtrl::isMinutesStringValid(const std::string& str)
-{
- U32 minutes;
- if (!LLStringUtil::convertToU32(str, minutes) || ((minutes <= MINUTES_MAX) && str.length() < 3))
- return true;
-
- return false;
-}
-
-// static
-bool LLTimeCtrl::isPMAMStringValid(const std::string& str)
-{
- S32 len = str.length();
-
- bool valid = (str[--len] == 'M') && (str[--len] == 'P' || str[len] == 'A');
-
- return valid;
-}
-
-// static
-U32 LLTimeCtrl::parseHours(const std::string& str)
-{
- U32 hours;
- if (LLStringUtil::convertToU32(str, hours) && (hours >= HOURS_MIN) && (hours <= HOURS_MAX))
- {
- return hours;
- }
- else
- {
- return HOURS_MIN;
- }
-}
-
-// static
-U32 LLTimeCtrl::parseMinutes(const std::string& str)
-{
- U32 minutes;
- // not sure of this fix - clang doesnt like compare minutes U32 to >= MINUTES_MIN (0) but MINUTES_MIN can change
- if (LLStringUtil::convertToU32(str, minutes) && ((S32)minutes >= MINUTES_MIN) && ((S32)minutes <= MINUTES_MAX))
- {
- return minutes;
- }
- else
- {
- return MINUTES_MIN;
- }
-}
-
-// static
-bool LLTimeCtrl::parseAMPM(const std::string& str)
-{
- return str == "PM";
-}
+/**
+ * @file lltimectrl.cpp
+ * @brief LLTimeCtrl base class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lltimectrl.h"
+
+#include "llui.h"
+#include "lluiconstants.h"
+
+#include "llbutton.h"
+#include "llfontgl.h"
+#include "lllineeditor.h"
+#include "llkeyboard.h"
+#include "llstring.h"
+#include "lltextbox.h"
+#include "lluictrlfactory.h"
+
+static LLDefaultChildRegistry::Register<LLTimeCtrl> time_r("time");
+
+const U32 AMPM_LEN = 3;
+const U32 MINUTES_MIN = 0;
+const U32 MINUTES_MAX = 59;
+const U32 HOURS_MIN = 1;
+const U32 HOURS_MAX = 12;
+const U32 MINUTES_PER_HOUR = 60;
+const U32 MINUTES_PER_DAY = 24 * MINUTES_PER_HOUR;
+
+class LLTimeValidatorImpl : public LLTextValidate::ValidatorImpl
+{
+public:
+ // virtual
+ bool validate(const std::string& str) override
+ {
+ std::string hours = LLTimeCtrl::getHoursString(str);
+ if (!LLTimeCtrl::isHoursStringValid(hours))
+ return setError("ValidatorInvalidHours", LLSD().with("STR", hours));
+
+ std::string minutes = LLTimeCtrl::getMinutesString(str);
+ if (!LLTimeCtrl::isMinutesStringValid(minutes))
+ return setError("ValidatorInvalidMinutes", LLSD().with("STR", minutes));
+
+ std::string ampm = LLTimeCtrl::getAMPMString(str);
+ if (!LLTimeCtrl::isPMAMStringValid(ampm))
+ return setError("ValidatorInvalidAMPM", LLSD().with("STR", ampm));
+
+ return resetError();
+ }
+
+ // virtual
+ bool validate(const LLWString& wstr) override
+ {
+ std::string str = wstring_to_utf8str(wstr);
+
+ return validate(str);
+ }
+} validateTimeImpl;
+LLTextValidate::Validator validateTime(validateTimeImpl);
+
+LLTimeCtrl::Params::Params()
+: label_width("label_width"),
+ snap_to("snap_to"),
+ allow_text_entry("allow_text_entry", true),
+ text_enabled_color("text_enabled_color"),
+ text_disabled_color("text_disabled_color"),
+ up_button("up_button"),
+ down_button("down_button")
+{}
+
+LLTimeCtrl::LLTimeCtrl(const LLTimeCtrl::Params& p)
+: LLUICtrl(p),
+ mLabelBox(NULL),
+ mTextEnabledColor(p.text_enabled_color()),
+ mTextDisabledColor(p.text_disabled_color()),
+ mTime(0),
+ mSnapToMin(5)
+{
+ static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0);
+ static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0);
+ static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0);
+ S32 centered_top = getRect().getHeight();
+ S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height;
+ S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40));
+ S32 editor_left = label_width + spinctrl_spacing;
+
+ //================= Label =================//
+ if( !p.label().empty() )
+ {
+ LLRect label_rect( 0, centered_top, label_width, centered_bottom );
+ LLTextBox::Params params;
+ params.name("TimeCtrl Label");
+ params.rect(label_rect);
+ params.initial_value(p.label());
+ if (p.font.isProvided())
+ {
+ params.font(p.font);
+ }
+ mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
+ addChild(mLabelBox);
+
+ editor_left = label_rect.mRight + spinctrl_spacing;
+ }
+
+ S32 editor_right = getRect().getWidth() - spinctrl_btn_width - spinctrl_spacing;
+
+ //================= Editor ================//
+ LLRect editor_rect( editor_left, centered_top, editor_right, centered_bottom );
+ LLLineEditor::Params params;
+ params.name("SpinCtrl Editor");
+ params.rect(editor_rect);
+ if (p.font.isProvided())
+ {
+ params.font(p.font);
+ }
+
+ params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
+ params.max_length.chars(8);
+ params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1));
+ mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
+ mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace);
+ mEditor->setPrevalidate(validateTime);
+ mEditor->setText(LLStringExplicit("12:00 AM"));
+ addChild(mEditor);
+
+ //================= Spin Buttons ==========//
+ LLButton::Params up_button_params(p.up_button);
+ up_button_params.rect = LLRect(editor_right + 1, getRect().getHeight(), editor_right + spinctrl_btn_width, getRect().getHeight() - spinctrl_btn_height);
+
+ up_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this));
+ up_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onUpBtn, this));
+ mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
+ addChild(mUpBtn);
+
+ LLButton::Params down_button_params(p.down_button);
+ down_button_params.rect = LLRect(editor_right + 1, getRect().getHeight() - spinctrl_btn_height, editor_right + spinctrl_btn_width, getRect().getHeight() - 2 * spinctrl_btn_height);
+ down_button_params.click_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this));
+ down_button_params.mouse_held_callback.function(boost::bind(&LLTimeCtrl::onDownBtn, this));
+ mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
+ addChild(mDownBtn);
+
+ setUseBoundingRect( true );
+}
+
+F32 LLTimeCtrl::getTime24() const
+{
+ // 0.0 - 23.99;
+ return mTime / 60.0f;
+}
+
+U32 LLTimeCtrl::getHours24() const
+{
+ return (U32) getTime24();
+}
+
+U32 LLTimeCtrl::getMinutes() const
+{
+ return mTime % MINUTES_PER_HOUR;
+}
+
+void LLTimeCtrl::setTime24(F32 time)
+{
+ time = llclamp(time, 0.0f, 23.99f); // fix out of range values
+ mTime = ll_round(time * MINUTES_PER_HOUR); // fixes values like 4.99999
+
+ updateText();
+}
+
+bool LLTimeCtrl::handleKeyHere(KEY key, MASK mask)
+{
+ if (mEditor->hasFocus())
+ {
+ if(key == KEY_UP)
+ {
+ onUpBtn();
+ return true;
+ }
+ if(key == KEY_DOWN)
+ {
+ onDownBtn();
+ return true;
+ }
+ if (key == KEY_RETURN)
+ {
+ onCommit();
+ return true;
+ }
+ }
+ return false;
+}
+
+void LLTimeCtrl::onUpBtn()
+{
+ switch(getEditingPart())
+ {
+ case HOURS:
+ increaseHours();
+ break;
+ case MINUTES:
+ increaseMinutes();
+ break;
+ case DAYPART:
+ switchDayPeriod();
+ break;
+ default:
+ break;
+ }
+
+ updateText();
+ onCommit();
+}
+
+void LLTimeCtrl::onDownBtn()
+{
+ switch(getEditingPart())
+ {
+ case HOURS:
+ decreaseHours();
+ break;
+ case MINUTES:
+ decreaseMinutes();
+ break;
+ case DAYPART:
+ switchDayPeriod();
+ break;
+ default:
+ break;
+ }
+
+ updateText();
+ onCommit();
+}
+
+void LLTimeCtrl::onFocusLost()
+{
+ updateText();
+ onCommit();
+ LLUICtrl::onFocusLost();
+}
+
+void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor)
+{
+ std::string time_str = line_editor->getText();
+ U32 h12 = parseHours(getHoursString(time_str));
+ U32 m = parseMinutes(getMinutesString(time_str));
+ bool pm = parseAMPM(getAMPMString(time_str));
+
+ if (h12 == 12)
+ {
+ h12 = 0;
+ }
+
+ U32 h24 = pm ? h12 + 12 : h12;
+
+ mTime = h24 * MINUTES_PER_HOUR + m;
+}
+
+void LLTimeCtrl::increaseMinutes()
+{
+ mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin);
+}
+
+void LLTimeCtrl::increaseHours()
+{
+ mTime = (mTime + MINUTES_PER_HOUR) % MINUTES_PER_DAY;
+}
+
+void LLTimeCtrl::decreaseMinutes()
+{
+ if (mTime < mSnapToMin)
+ {
+ mTime = MINUTES_PER_DAY - mTime;
+ }
+
+ mTime -= (mTime % mSnapToMin) ? mTime % mSnapToMin : mSnapToMin;
+}
+
+void LLTimeCtrl::decreaseHours()
+{
+ if (mTime < MINUTES_PER_HOUR)
+ {
+ mTime = 23 * MINUTES_PER_HOUR + mTime;
+ }
+ else
+ {
+ mTime -= MINUTES_PER_HOUR;
+ }
+}
+
+bool LLTimeCtrl::isPM() const
+{
+ return mTime >= (MINUTES_PER_DAY / 2);
+}
+
+void LLTimeCtrl::switchDayPeriod()
+{
+ if (isPM())
+ {
+ mTime -= MINUTES_PER_DAY / 2;
+ }
+ else
+ {
+ mTime += MINUTES_PER_DAY / 2;
+ }
+}
+
+void LLTimeCtrl::updateText()
+{
+ U32 h24 = getHours24();
+ U32 m = getMinutes();
+ U32 h12 = h24 > 12 ? h24 - 12 : h24;
+
+ if (h12 == 0)
+ h12 = 12;
+
+ mEditor->setText(llformat("%d:%02d %s", h12, m, isPM() ? "PM":"AM"));
+}
+
+LLTimeCtrl::EEditingPart LLTimeCtrl::getEditingPart()
+{
+ S32 cur_pos = mEditor->getCursor();
+ std::string time_str = mEditor->getText();
+
+ S32 colon_index = time_str.find_first_of(':');
+
+ if (cur_pos <= colon_index)
+ {
+ return HOURS;
+ }
+ else if (cur_pos > colon_index && cur_pos <= (S32)(time_str.length() - AMPM_LEN))
+ {
+ return MINUTES;
+ }
+ else if (cur_pos > (S32)(time_str.length() - AMPM_LEN))
+ {
+ return DAYPART;
+ }
+
+ return NONE;
+}
+
+// static
+std::string LLTimeCtrl::getHoursString(const std::string& str)
+{
+ size_t colon_index = str.find_first_of(':');
+ std::string hours_str = str.substr(0, colon_index);
+
+ return hours_str;
+}
+
+// static
+std::string LLTimeCtrl::getMinutesString(const std::string& str)
+{
+ size_t colon_index = str.find_first_of(':');
+ ++colon_index;
+
+ int minutes_len = str.length() - colon_index - AMPM_LEN;
+ std::string minutes_str = str.substr(colon_index, minutes_len);
+
+ return minutes_str;
+}
+
+// static
+std::string LLTimeCtrl::getAMPMString(const std::string& str)
+{
+ return str.substr(str.size() - 2, 2); // returns last two characters
+}
+
+// static
+bool LLTimeCtrl::isHoursStringValid(const std::string& str)
+{
+ U32 hours;
+ if ((!LLStringUtil::convertToU32(str, hours) || (hours <= HOURS_MAX)) && str.length() < 3)
+ return true;
+
+ return false;
+}
+
+// static
+bool LLTimeCtrl::isMinutesStringValid(const std::string& str)
+{
+ U32 minutes;
+ if (!LLStringUtil::convertToU32(str, minutes) || ((minutes <= MINUTES_MAX) && str.length() < 3))
+ return true;
+
+ return false;
+}
+
+// static
+bool LLTimeCtrl::isPMAMStringValid(const std::string& str)
+{
+ S32 len = str.length();
+
+ bool valid = (str[--len] == 'M') && (str[--len] == 'P' || str[len] == 'A');
+
+ return valid;
+}
+
+// static
+U32 LLTimeCtrl::parseHours(const std::string& str)
+{
+ U32 hours;
+ if (LLStringUtil::convertToU32(str, hours) && (hours >= HOURS_MIN) && (hours <= HOURS_MAX))
+ {
+ return hours;
+ }
+ else
+ {
+ return HOURS_MIN;
+ }
+}
+
+// static
+U32 LLTimeCtrl::parseMinutes(const std::string& str)
+{
+ U32 minutes;
+ // not sure of this fix - clang doesnt like compare minutes U32 to >= MINUTES_MIN (0) but MINUTES_MIN can change
+ if (LLStringUtil::convertToU32(str, minutes) && ((S32)minutes >= MINUTES_MIN) && ((S32)minutes <= MINUTES_MAX))
+ {
+ return minutes;
+ }
+ else
+ {
+ return MINUTES_MIN;
+ }
+}
+
+// static
+bool LLTimeCtrl::parseAMPM(const std::string& str)
+{
+ return str == "PM";
+}