summaryrefslogtreecommitdiff
path: root/indra/newview/llpanelenvironment.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llpanelenvironment.cpp')
-rw-r--r--indra/newview/llpanelenvironment.cpp934
1 files changed, 934 insertions, 0 deletions
diff --git a/indra/newview/llpanelenvironment.cpp b/indra/newview/llpanelenvironment.cpp
new file mode 100644
index 0000000000..e3be46f1af
--- /dev/null
+++ b/indra/newview/llpanelenvironment.cpp
@@ -0,0 +1,934 @@
+/**
+ * @file llpanelenvironment.cpp
+ * @brief LLPanelExperiences class implementation
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, 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 "llviewerprecompiledheaders.h"
+
+
+#include "llpanelprofile.h"
+#include "lluictrlfactory.h"
+#include "llexperiencecache.h"
+#include "llagent.h"
+#include "llparcel.h"
+
+#include "llviewerregion.h"
+#include "llpanelenvironment.h"
+#include "llslurl.h"
+#include "lllayoutstack.h"
+
+#include "llfloater.h"
+#include "llfloaterreg.h"
+#include "llfloatereditextdaycycle.h"
+#include "llmultisliderctrl.h"
+#include "llsettingsvo.h"
+
+#include "llappviewer.h"
+#include "llcallbacklist.h"
+#include "llviewerparcelmgr.h"
+
+#include "llinventorymodel.h"
+
+//=========================================================================
+namespace
+{
+ const std::string FLOATER_DAY_CYCLE_EDIT("env_edit_extdaycycle");
+}
+
+//=========================================================================
+const std::string LLPanelEnvironmentInfo::RDG_ENVIRONMENT_SELECT("rdg_environment_select");
+const std::string LLPanelEnvironmentInfo::RDO_USEDEFAULT("rdo_use_xxx_setting");
+const std::string LLPanelEnvironmentInfo::RDO_USEINV("rdo_use_inv_setting");
+const std::string LLPanelEnvironmentInfo::RDO_USECUSTOM("rdo_use_custom_setting");
+const std::string LLPanelEnvironmentInfo::EDT_INVNAME("edt_inventory_name");
+const std::string LLPanelEnvironmentInfo::BTN_SELECTINV("btn_select_inventory");
+const std::string LLPanelEnvironmentInfo::BTN_EDIT("btn_edit");
+const std::string LLPanelEnvironmentInfo::SLD_DAYLENGTH("sld_day_length");
+const std::string LLPanelEnvironmentInfo::SLD_DAYOFFSET("sld_day_offset");
+const std::string LLPanelEnvironmentInfo::SLD_ALTITUDES("sld_altitudes");
+const std::string LLPanelEnvironmentInfo::ICN_GROUND("icon_ground");
+const std::string LLPanelEnvironmentInfo::CHK_ALLOWOVERRIDE("chk_allow_override");
+const std::string LLPanelEnvironmentInfo::BTN_APPLY("btn_apply");
+const std::string LLPanelEnvironmentInfo::BTN_CANCEL("btn_cancel");
+const std::string LLPanelEnvironmentInfo::LBL_TIMEOFDAY("lbl_apparent_time");
+const std::string LLPanelEnvironmentInfo::PNL_SETTINGS("pnl_environment_config");
+const std::string LLPanelEnvironmentInfo::PNL_ENVIRONMENT_ALTITUDES("pnl_environment_altitudes");
+const std::string LLPanelEnvironmentInfo::PNL_BUTTONS("pnl_environment_buttons");
+const std::string LLPanelEnvironmentInfo::PNL_DISABLED("pnl_environment_disabled");
+const std::string LLPanelEnvironmentInfo::TXT_DISABLED("txt_environment_disabled");
+const std::string LLPanelEnvironmentInfo::SDT_DROP_TARGET("sdt_drop_target");
+
+const std::string LLPanelEnvironmentInfo::STR_LABEL_USEDEFAULT("str_label_use_default");
+const std::string LLPanelEnvironmentInfo::STR_LABEL_USEREGION("str_label_use_region");
+const std::string LLPanelEnvironmentInfo::STR_LABEL_UNKNOWNINV("str_unknow_inventory");
+const std::string LLPanelEnvironmentInfo::STR_ALTITUDE_DESCRIPTION("str_altitude_desription");
+const std::string LLPanelEnvironmentInfo::STR_NO_PARCEL("str_no_parcel");
+const std::string LLPanelEnvironmentInfo::STR_CROSS_REGION("str_cross_region");
+const std::string LLPanelEnvironmentInfo::STR_LEGACY("str_legacy");
+
+const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_DAYCYCLE(0x01 << 0);
+const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_DAYLENGTH(0x01 << 1);
+const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_DAYOFFSET(0x01 << 2);
+const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_ALTITUDES(0x01 << 3);
+
+const U32 LLPanelEnvironmentInfo::DIRTY_FLAG_MASK(
+ LLPanelEnvironmentInfo::DIRTY_FLAG_DAYCYCLE |
+ LLPanelEnvironmentInfo::DIRTY_FLAG_DAYLENGTH |
+ LLPanelEnvironmentInfo::DIRTY_FLAG_DAYOFFSET |
+ LLPanelEnvironmentInfo::DIRTY_FLAG_ALTITUDES);
+
+const U32 ALTITUDE_SLIDER_COUNT = 3;
+
+const std::string alt_sliders[] = {
+ "sld1",
+ "sld2",
+ "sld3",
+};
+
+const std::string alt_labels[] = {
+ "alt1",
+ "alt2",
+ "alt3",
+ "ground",
+};
+
+
+static LLDefaultChildRegistry::Register<LLSettingsDropTarget> r("settings_drop_target");
+
+//=========================================================================
+LLPanelEnvironmentInfo::LLPanelEnvironmentInfo():
+ mCurrentEnvironment(),
+ mDirtyFlag(0),
+ mEditorLastParcelId(INVALID_PARCEL_ID),
+ mCrossRegion(false),
+ mNoSelection(false),
+ mNoEnvironment(false),
+ mCurEnvVersion(INVALID_PARCEL_ENVIRONMENT_VERSION),
+ mSettingsFloater(),
+ mEditFloater()
+{
+}
+
+LLPanelEnvironmentInfo::~LLPanelEnvironmentInfo()
+{
+ if (mChangeMonitor.connected())
+ mChangeMonitor.disconnect();
+ if (mCommitConnection.connected())
+ mCommitConnection.disconnect();
+}
+
+BOOL LLPanelEnvironmentInfo::postBuild()
+{
+ getChild<LLUICtrl>(RDG_ENVIRONMENT_SELECT)->setCommitCallback([this](LLUICtrl *, const LLSD &){ onSwitchDefaultSelection(); });
+ getChild<LLUICtrl>(BTN_SELECTINV)->setCommitCallback([this](LLUICtrl *, const LLSD &){ onBtnSelect(); });
+ getChild<LLUICtrl>(BTN_EDIT)->setCommitCallback([this](LLUICtrl *, const LLSD &){ onBtnEdit(); });
+ getChild<LLUICtrl>(BTN_APPLY)->setCommitCallback([this](LLUICtrl *, const LLSD &){ onBtnApply(); });
+ getChild<LLUICtrl>(BTN_CANCEL)->setCommitCallback([this](LLUICtrl *, const LLSD &){ onBtnReset(); });
+
+ getChild<LLUICtrl>(SLD_DAYLENGTH)->setCommitCallback([this](LLUICtrl *, const LLSD &value) { onSldDayLengthChanged(value.asReal()); });
+ getChild<LLUICtrl>(SLD_DAYOFFSET)->setCommitCallback([this](LLUICtrl *, const LLSD &value) { onSldDayOffsetChanged(value.asReal()); });
+
+ getChild<LLMultiSliderCtrl>(SLD_ALTITUDES)->setCommitCallback([this](LLUICtrl *cntrl, const LLSD &value) { onAltSliderCallback(cntrl, value); });
+
+ mChangeMonitor = LLEnvironment::instance().setEnvironmentChanged([this](LLEnvironment::EnvSelection_t env, S32 version) { onEnvironmentChanged(env, version); });
+
+ getChild<LLSettingsDropTarget>(SDT_DROP_TARGET)->setPanel(this);
+
+ return TRUE;
+}
+
+// virtual
+void LLPanelEnvironmentInfo::onOpen(const LLSD& key)
+{
+ refreshFromSource();
+}
+
+// virtual
+void LLPanelEnvironmentInfo::onVisibilityChange(BOOL new_visibility)
+{
+ if (new_visibility)
+ {
+ gIdleCallbacks.addFunction(onIdlePlay, this);
+ }
+ else
+ {
+ LLFloaterSettingsPicker *picker = getSettingsPicker(false);
+ if (picker)
+ {
+ picker->closeFloater();
+ }
+
+ gIdleCallbacks.deleteFunction(onIdlePlay, this);
+ LLFloaterEditExtDayCycle *dayeditor = getEditFloater(false);
+ if (mCommitConnection.connected())
+ mCommitConnection.disconnect();
+
+ if (dayeditor)
+ {
+ if (dayeditor->isDirty())
+ dayeditor->refresh();
+ else
+ {
+ dayeditor->closeFloater();
+ mEditFloater.markDead();
+ }
+ }
+ }
+
+}
+
+void LLPanelEnvironmentInfo::refresh()
+{
+ if (gDisconnected)
+ return;
+
+ if (!setControlsEnabled(canEdit()))
+ return;
+
+ if (!mCurrentEnvironment)
+ {
+ return;
+ }
+
+ S32 rdo_selection = 0;
+ if ((!mCurrentEnvironment->mDayCycle) ||
+ ((mCurrentEnvironment->mParcelId == INVALID_PARCEL_ID) && (mCurrentEnvironment->mDayCycle->getAssetId() == LLSettingsDay::GetDefaultAssetId() )))
+ {
+ getChild<LLUICtrl>(EDT_INVNAME)->setValue("");
+ }
+ else if (!mCurrentEnvironment->mDayCycle->getAssetId().isNull())
+ {
+ rdo_selection = 1;
+
+ LLUUID asset_id = mCurrentEnvironment->mDayCycle->getAssetId();
+
+ std::string inventoryname = getInventoryNameForAssetId(asset_id);
+
+ if (inventoryname.empty())
+ inventoryname = "(" + mCurrentEnvironment->mDayCycle->getName() + ")";
+
+ getChild<LLUICtrl>(EDT_INVNAME)->setValue(inventoryname);
+ }
+ else
+ { // asset id is null so this is a custom environment
+ rdo_selection = 2;
+ getChild<LLUICtrl>(EDT_INVNAME)->setValue("");
+ }
+ getChild<LLRadioGroup>(RDG_ENVIRONMENT_SELECT)->setSelectedIndex(rdo_selection);
+
+ F32Hours daylength(mCurrentEnvironment->mDayLength);
+ F32Hours dayoffset(mCurrentEnvironment->mDayOffset);
+
+ if (dayoffset.value() > 12.0f)
+ dayoffset -= F32Hours(24.0);
+
+ getChild<LLSliderCtrl>(SLD_DAYLENGTH)->setValue(daylength.value());
+ getChild<LLSliderCtrl>(SLD_DAYOFFSET)->setValue(dayoffset.value());
+ getChild<LLSliderCtrl>(SLD_DAYLENGTH)->setEnabled(canEdit() && (rdo_selection != 0) && !mCurrentEnvironment->mIsLegacy);
+ getChild<LLSliderCtrl>(SLD_DAYOFFSET)->setEnabled(canEdit() && (rdo_selection != 0) && !mCurrentEnvironment->mIsLegacy);
+
+ udpateApparentTimeOfDay();
+
+ updateEditFloater(mCurrentEnvironment, canEdit());
+
+ LLEnvironment::altitude_list_t altitudes = LLEnvironment::instance().getRegionAltitudes();
+ if (altitudes.size() > 0)
+ {
+ LLMultiSliderCtrl *sld = getChild<LLMultiSliderCtrl>(SLD_ALTITUDES);
+ sld->clear();
+
+ for (S32 idx = 0; idx < ALTITUDE_SLIDER_COUNT; ++idx)
+ {
+ sld->addSlider(altitudes[idx + 1], alt_sliders[idx]);
+ updateAltLabel(alt_labels[idx], idx + 2, altitudes[idx+1]);
+ mAltitudes[alt_sliders[idx]] = AltitudeData(idx+1, idx, altitudes[idx+1]);
+ }
+ if (sld->getCurNumSliders() != ALTITUDE_SLIDER_COUNT)
+ {
+ LL_WARNS("ENVPANEL") << "Failed to add altitude sliders!" << LL_ENDL;
+ }
+ readjustAltLabels();
+ }
+
+}
+
+std::string LLPanelEnvironmentInfo::getInventoryNameForAssetId(LLUUID asset_id)
+{
+ std::string name(LLFloaterSettingsPicker::findItemName(asset_id, false, false));
+
+ if (name.empty())
+ return getString(STR_LABEL_UNKNOWNINV);
+ return name;
+}
+
+LLFloaterSettingsPicker * LLPanelEnvironmentInfo::getSettingsPicker(bool create)
+{
+ LLFloaterSettingsPicker *picker = static_cast<LLFloaterSettingsPicker *>(mSettingsFloater.get());
+
+ // Show the dialog
+ if (!picker && create)
+ {
+ picker = new LLFloaterSettingsPicker(this,
+ LLUUID::null, "SELECT SETTINGS");
+
+ mSettingsFloater = picker->getHandle();
+
+ picker->setCommitCallback([this](LLUICtrl *, const LLSD &data){ onPickerCommitted(data.asUUID()); });
+ }
+
+ return picker;
+}
+
+LLFloaterEditExtDayCycle * LLPanelEnvironmentInfo::getEditFloater(bool create)
+{
+ static const S32 FOURHOURS(4 * 60 * 60);
+ LLFloaterEditExtDayCycle *editor = static_cast<LLFloaterEditExtDayCycle *>(mEditFloater.get());
+
+ // Show the dialog
+ if (!editor && create)
+ {
+ LLSD params(LLSDMap(LLFloaterEditExtDayCycle::KEY_EDIT_CONTEXT, isRegion() ? LLFloaterEditExtDayCycle::CONTEXT_REGION : LLFloaterEditExtDayCycle::CONTEXT_PARCEL)
+ (LLFloaterEditExtDayCycle::KEY_DAY_LENGTH, mCurrentEnvironment ? (S32)(mCurrentEnvironment->mDayLength.value()) : FOURHOURS));
+
+ editor = (LLFloaterEditExtDayCycle *)LLFloaterReg::getInstance(FLOATER_DAY_CYCLE_EDIT, params);
+
+ if (!editor)
+ return nullptr;
+ mEditFloater = editor->getHandle();
+ }
+
+ if (editor && !mCommitConnection.connected())
+ mCommitConnection = editor->setEditCommitSignal([this](LLSettingsDay::ptr_t pday) { onEditCommitted(pday); });
+
+ return editor;
+}
+
+
+void LLPanelEnvironmentInfo::updateEditFloater(const LLEnvironment::EnvironmentInfo::ptr_t &nextenv, bool enable)
+{
+ LLFloaterEditExtDayCycle *dayeditor(getEditFloater(false));
+
+ if (!dayeditor)
+ return;
+
+ if (!nextenv || !nextenv->mDayCycle || !enable)
+ {
+ if (mCommitConnection.connected())
+ mCommitConnection.disconnect();
+
+ if (dayeditor->isDirty())
+ dayeditor->refresh();
+ else
+ dayeditor->closeFloater();
+ }
+ else if (dayeditor->getEditingAssetId() != nextenv->mDayCycle->getAssetId()
+ || mEditorLastParcelId != nextenv->mParcelId
+ || mEditorLastRegionId != nextenv->mRegionId)
+ {
+ // Ignore dirty
+ // If parcel selection changed whatever we do except saving to inventory with
+ // old settings will be invalid.
+ mEditorLastParcelId = nextenv->mParcelId;
+ mEditorLastRegionId = nextenv->mRegionId;
+ dayeditor->setEditDayCycle(nextenv->mDayCycle);
+ }
+}
+
+bool LLPanelEnvironmentInfo::setControlsEnabled(bool enabled)
+{
+ bool is_unavailable(false);
+ bool is_legacy = (mCurrentEnvironment) ? mCurrentEnvironment->mIsLegacy : true;
+
+ if (mNoEnvironment || (!LLEnvironment::instance().isExtendedEnvironmentEnabled() && !isRegion()))
+ {
+ is_unavailable = true;
+ getChild<LLTextBox>(TXT_DISABLED)->setText(getString(STR_LEGACY));
+ }
+ else if (mNoSelection)
+ {
+ is_unavailable = true;
+ getChild<LLTextBox>(TXT_DISABLED)->setText(getString(STR_NO_PARCEL));
+ }
+ else if (mCrossRegion)
+ {
+ is_unavailable = true;
+ getChild<LLTextBox>(TXT_DISABLED)->setText(getString(STR_CROSS_REGION));
+ }
+
+ if (is_unavailable)
+ {
+ getChild<LLUICtrl>(PNL_SETTINGS)->setVisible(false);
+ getChild<LLUICtrl>(PNL_BUTTONS)->setVisible(false);
+ getChild<LLUICtrl>(PNL_DISABLED)->setVisible(true);
+ getChild<LLUICtrl>(PNL_ENVIRONMENT_ALTITUDES)->setVisible(FALSE);
+
+ updateEditFloater(mCurrentEnvironment, false);
+
+ return false;
+ }
+ getChild<LLUICtrl>(PNL_SETTINGS)->setVisible(true);
+ getChild<LLUICtrl>(PNL_BUTTONS)->setVisible(true);
+ getChild<LLUICtrl>(PNL_DISABLED)->setVisible(false);
+
+ getChild<LLUICtrl>(PNL_ENVIRONMENT_ALTITUDES)->setVisible(isRegion() && LLEnvironment::instance().isExtendedEnvironmentEnabled());
+
+ S32 rdo_selection = getChild<LLRadioGroup>(RDG_ENVIRONMENT_SELECT)->getSelectedIndex();
+
+ bool can_enable = enabled && mCurrentEnvironment && mCurEnvVersion != INVALID_PARCEL_ENVIRONMENT_VERSION;
+ getChild<LLUICtrl>(RDG_ENVIRONMENT_SELECT)->setEnabled(can_enable);
+ getChild<LLUICtrl>(RDO_USEDEFAULT)->setEnabled(can_enable && !is_legacy);
+ getChild<LLUICtrl>(RDO_USEINV)->setEnabled(false); // these two are selected automatically based on
+ getChild<LLUICtrl>(RDO_USECUSTOM)->setEnabled(false);
+ getChild<LLUICtrl>(EDT_INVNAME)->setEnabled(FALSE);
+ getChild<LLUICtrl>(BTN_SELECTINV)->setEnabled(can_enable && !is_legacy);
+ getChild<LLUICtrl>(BTN_EDIT)->setEnabled(can_enable);
+ getChild<LLUICtrl>(SLD_DAYLENGTH)->setEnabled(can_enable && (rdo_selection != 0) && !is_legacy);
+ getChild<LLUICtrl>(SLD_DAYOFFSET)->setEnabled(can_enable && (rdo_selection != 0) && !is_legacy);
+ getChild<LLUICtrl>(SLD_ALTITUDES)->setEnabled(can_enable && isRegion() && !is_legacy);
+ getChild<LLUICtrl>(ICN_GROUND)->setColor((can_enable && isRegion() && !is_legacy) ? LLColor4::white : LLColor4::grey % 0.8f);
+ getChild<LLUICtrl>(PNL_ENVIRONMENT_ALTITUDES)->setEnabled(can_enable && isRegion() && !is_legacy);
+ getChild<LLUICtrl>(CHK_ALLOWOVERRIDE)->setEnabled(can_enable && isRegion() && !is_legacy);
+ getChild<LLUICtrl>(BTN_APPLY)->setEnabled(can_enable && (mDirtyFlag != 0));
+ getChild<LLUICtrl>(BTN_CANCEL)->setEnabled(enabled && (mDirtyFlag != 0));
+
+ getChild<LLSettingsDropTarget>(SDT_DROP_TARGET)->setDndEnabled(enabled && !is_legacy);
+
+ return true;
+}
+
+void LLPanelEnvironmentInfo::setApplyProgress(bool started)
+{
+// LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("progress_indicator");
+//
+// indicator->setVisible(started);
+//
+// if (started)
+// {
+// indicator->start();
+// }
+// else
+// {
+// indicator->stop();
+// }
+}
+
+void LLPanelEnvironmentInfo::setDirtyFlag(U32 flag)
+{
+ bool can_edit = canEdit();
+ mDirtyFlag |= flag;
+ getChildView(BTN_APPLY)->setEnabled((mDirtyFlag != 0) && mCurrentEnvironment && mCurEnvVersion != INVALID_PARCEL_ENVIRONMENT_VERSION && can_edit);
+ getChildView(BTN_CANCEL)->setEnabled((mDirtyFlag != 0) && mCurrentEnvironment && can_edit);
+}
+
+void LLPanelEnvironmentInfo::clearDirtyFlag(U32 flag)
+{
+ bool can_edit = canEdit();
+ mDirtyFlag &= ~flag;
+ getChildView(BTN_APPLY)->setEnabled((mDirtyFlag != 0) && mCurrentEnvironment && mCurEnvVersion != INVALID_PARCEL_ENVIRONMENT_VERSION && can_edit);
+ getChildView(BTN_CANCEL)->setEnabled((mDirtyFlag != 0) && mCurrentEnvironment && can_edit);
+}
+
+void LLPanelEnvironmentInfo::updateAltLabel(const std::string &alt_name, U32 sky_index, F32 alt_value)
+{
+ LLMultiSliderCtrl *sld = getChild<LLMultiSliderCtrl>(SLD_ALTITUDES);
+ LLRect sld_rect = sld->getRect();
+ S32 sld_range = sld_rect.getHeight();
+ S32 sld_bottom = sld_rect.mBottom;
+ S32 sld_offset = sld_rect.getWidth(); // Roughly identical to thumb's width in slider.
+ S32 pos = (sld_range - sld_offset) * ((alt_value - 100) / (4000 - 100));
+
+ // get related text box
+ LLTextBox* text = getChild<LLTextBox>(alt_name);
+ if (text)
+ {
+ // move related text box
+ LLRect rect = text->getRect();
+ S32 height = rect.getHeight();
+ rect.mBottom = sld_bottom + (sld_offset / 2 + 1) + pos - (height / 2);
+ rect.mTop = rect.mBottom + height;
+ text->setRect(rect);
+
+ // update text
+ std::ostringstream convert;
+ convert << alt_value;
+ text->setTextArg("[ALTITUDE]", convert.str());
+ convert.str("");
+ convert.clear();
+ convert << sky_index;
+ text->setTextArg("[INDEX]", convert.str());
+ }
+}
+
+void LLPanelEnvironmentInfo::readjustAltLabels()
+{
+ // Restore ground label position
+ LLView* icon = getChild<LLView>(ICN_GROUND);
+ LLTextBox* text = getChild<LLTextBox>(alt_labels[ALTITUDE_SLIDER_COUNT]); // one more field then sliders
+ LLRect ground_text_rect = text->getRect();
+ LLRect icon_rect = icon->getRect();
+ S32 height = ground_text_rect.getHeight();
+ ground_text_rect.mBottom = icon_rect.mBottom + (icon_rect.getHeight()/2) - (height/2);
+ ground_text_rect.mTop = ground_text_rect.mBottom + height;
+ text->setRect(ground_text_rect);
+
+ // Re-adjust all labels
+ // Very simple "adjust after the fact" method
+ // Note: labels are unordered, labels are 1 above sliders due to 'ground'
+
+ for (U32 i = 0; i < ALTITUDE_SLIDER_COUNT; i++)
+ {
+ LLTextBox* text_cmp = getChild<LLTextBox>(alt_labels[i]);
+
+ for (U32 j = i + 1; j <= ALTITUDE_SLIDER_COUNT; j++)
+ {
+ LLTextBox* text_intr = getChild<LLTextBox>(alt_labels[j]);
+ if (text_cmp && text_intr)
+ {
+ LLRect cmp_rect = text_cmp->getRect();
+ LLRect intr_rect = text_intr->getRect();
+ S32 shift = 0;
+ if (cmp_rect.mBottom <= intr_rect.mTop && cmp_rect.mBottom >= intr_rect.mBottom)
+ {
+ // Aproximate shift
+ // We probably will need more cycle runs over all labels to get accurate one
+ // At the moment single cycle should do since we have too little elements to do something complicated
+ shift = (cmp_rect.mBottom - intr_rect.mTop) / 2;
+ }
+ else if (cmp_rect.mTop >= intr_rect.mBottom && cmp_rect.mTop <= intr_rect.mTop)
+ {
+ // Aproximate shift
+ shift = (cmp_rect.mTop - intr_rect.mBottom) / 2;
+ }
+ if (shift != 0)
+ {
+ cmp_rect.translate(0, -shift);
+ text_cmp->setRect(cmp_rect);
+
+ intr_rect.translate(0, shift);
+ text_intr->setRect(intr_rect);
+ }
+ }
+ }
+ }
+}
+
+void LLPanelEnvironmentInfo::onSwitchDefaultSelection()
+{
+ bool can_edit = canEdit();
+ setDirtyFlag(DIRTY_FLAG_DAYCYCLE);
+
+ S32 rdo_selection = getChild<LLRadioGroup>(RDG_ENVIRONMENT_SELECT)->getSelectedIndex();
+ getChild<LLUICtrl>(SLD_DAYLENGTH)->setEnabled(can_edit && (rdo_selection != 0));
+ getChild<LLUICtrl>(SLD_DAYOFFSET)->setEnabled(can_edit && (rdo_selection != 0));
+}
+
+void LLPanelEnvironmentInfo::onSldDayLengthChanged(F32 value)
+{
+ F32Hours daylength(value);
+
+ mCurrentEnvironment->mDayLength = daylength;
+ setDirtyFlag(DIRTY_FLAG_DAYLENGTH);
+
+ udpateApparentTimeOfDay();
+}
+
+void LLPanelEnvironmentInfo::onSldDayOffsetChanged(F32 value)
+{
+ F32Hours dayoffset(value);
+
+ if (dayoffset.value() <= 0.0f)
+ dayoffset += F32Hours(24.0);
+
+ mCurrentEnvironment->mDayOffset = dayoffset;
+ setDirtyFlag(DIRTY_FLAG_DAYOFFSET);
+
+ udpateApparentTimeOfDay();
+}
+
+void LLPanelEnvironmentInfo::onAltSliderCallback(LLUICtrl *cntrl, const LLSD &data)
+{
+ LLMultiSliderCtrl *sld = (LLMultiSliderCtrl *)cntrl;
+ std::string sld_name = sld->getCurSlider();
+ F32 sld_value = sld->getCurSliderValue();
+
+ mAltitudes[sld_name].mAltitude = sld_value;
+
+ // update all labels since we could have jumped multiple and we will need to readjust
+ // (or sort by altitude, too little elements, so I didn't bother with efficiency)
+ altitudes_data_t::iterator end = mAltitudes.end();
+ altitudes_data_t::iterator iter = mAltitudes.begin();
+ altitudes_data_t::iterator iter2;
+ U32 new_index;
+ while (iter != end)
+ {
+ iter2 = mAltitudes.begin();
+ new_index = 1;
+ while (iter2 != end)
+ {
+ if (iter->second.mAltitude > iter2->second.mAltitude)
+ {
+ new_index++;
+ }
+ iter2++;
+ }
+ iter->second.mAltitudeIndex = new_index;
+ updateAltLabel(alt_labels[iter->second.mLabelIndex], iter->second.mAltitudeIndex + 1, iter->second.mAltitude);
+ iter++;
+ }
+
+ readjustAltLabels();
+ setDirtyFlag(DIRTY_FLAG_ALTITUDES);
+}
+
+void LLPanelEnvironmentInfo::onBtnApply()
+{
+ doApply();
+}
+
+void LLPanelEnvironmentInfo::onBtnReset()
+{
+ mCurrentEnvironment.reset();
+ refreshFromSource();
+}
+
+void LLPanelEnvironmentInfo::onBtnEdit()
+{
+ static const S32 FOURHOURS(4 * 60 * 60);
+
+ LLFloaterEditExtDayCycle *dayeditor = getEditFloater();
+
+ LLSD params(LLSDMap(LLFloaterEditExtDayCycle::KEY_EDIT_CONTEXT, isRegion() ? LLFloaterEditExtDayCycle::VALUE_CONTEXT_REGION : LLFloaterEditExtDayCycle::VALUE_CONTEXT_PARCEL)
+ (LLFloaterEditExtDayCycle::KEY_DAY_LENGTH, mCurrentEnvironment ? (S32)(mCurrentEnvironment->mDayLength.value()) : FOURHOURS)
+ (LLFloaterEditExtDayCycle::KEY_CANMOD, LLSD::Boolean(true)));
+
+ dayeditor->openFloater(params);
+ if (mCurrentEnvironment && mCurrentEnvironment->mDayCycle)
+ dayeditor->setEditDayCycle(mCurrentEnvironment->mDayCycle);
+ else
+ dayeditor->setEditDefaultDayCycle();
+}
+
+void LLPanelEnvironmentInfo::onBtnSelect()
+{
+ LLFloaterSettingsPicker *picker = getSettingsPicker();
+ if (picker)
+ {
+ LLUUID item_id;
+ if (mCurrentEnvironment && mCurrentEnvironment->mDayCycle)
+ {
+ item_id = LLFloaterSettingsPicker::findItemID(mCurrentEnvironment->mDayCycle->getAssetId(), false, false);
+ }
+ picker->setSettingsFilter(LLSettingsType::ST_NONE);
+ picker->setSettingsItemId(item_id);
+ picker->openFloater();
+ picker->setFocus(TRUE);
+ }
+}
+
+
+void LLPanelEnvironmentInfo::doApply()
+{
+ S32 parcel_id = getParcelId();
+
+ if (getIsDirtyFlag(DIRTY_FLAG_MASK))
+ {
+ LLHandle<LLPanel> that_h = getHandle();
+ LLEnvironment::altitudes_vect_t alts;
+
+ S32 rdo_selection = getChild<LLRadioGroup>(RDG_ENVIRONMENT_SELECT)->getSelectedIndex();
+
+ if (isRegion() && getIsDirtyFlag(DIRTY_FLAG_ALTITUDES))
+ {
+ altitudes_data_t::iterator it;
+ for (auto alt : mAltitudes)
+ {
+ alts.push_back(alt.second.mAltitude);
+ }
+ }
+
+ if (rdo_selection == 0)
+ {
+ LLEnvironment::instance().resetParcel(parcel_id,
+ [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) { _onEnvironmentReceived(that_h, parcel_id, envifo); });
+ }
+ else if (rdo_selection == 1)
+ {
+ if (!mCurrentEnvironment)
+ {
+ // Attempting to save mid update?
+ LL_WARNS("ENVPANEL") << "Failed to apply changes from editor! Dirty state: " << mDirtyFlag << " update state: " << mCurEnvVersion << LL_ENDL;
+ return;
+ }
+ LLEnvironment::instance().updateParcel(parcel_id,
+ mCurrentEnvironment->mDayCycle->getAssetId(), std::string(), mCurrentEnvironment->mDayLength.value(),
+ mCurrentEnvironment->mDayOffset.value(), alts,
+ [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) { _onEnvironmentReceived(that_h, parcel_id, envifo); });
+ }
+ else
+ {
+ if (!mCurrentEnvironment)
+ {
+ // Attempting to save mid update?
+ LL_WARNS("ENVPANEL") << "Failed to apply changes from editor! Dirty state: " << mDirtyFlag << " update state: " << mCurEnvVersion << LL_ENDL;
+ return;
+ }
+ LLEnvironment::instance().updateParcel(parcel_id,
+ mCurrentEnvironment->mDayCycle, mCurrentEnvironment->mDayLength.value(), mCurrentEnvironment->mDayOffset.value(), alts,
+ [that_h](S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo) { _onEnvironmentReceived(that_h, parcel_id, envifo); });
+ }
+
+ setControlsEnabled(false);
+ }
+}
+
+
+void LLPanelEnvironmentInfo::udpateApparentTimeOfDay()
+{
+ static const F32 SECONDSINDAY(24.0 * 60.0 * 60.0);
+
+ if ((!mCurrentEnvironment) || (mCurrentEnvironment->mDayLength.value() < 1.0) || (mCurrentEnvironment->mDayOffset.value() < 1.0))
+ {
+ getChild<LLUICtrl>(LBL_TIMEOFDAY)->setVisible(false);
+ return;
+ }
+ getChild<LLUICtrl>(LBL_TIMEOFDAY)->setVisible(true);
+
+ S32Seconds now(LLDate::now().secondsSinceEpoch());
+
+ now += mCurrentEnvironment->mDayOffset;
+
+ F32 perc = (F32)(now.value() % mCurrentEnvironment->mDayLength.value()) / (F32)(mCurrentEnvironment->mDayLength.value());
+
+ S32Seconds secondofday((S32)(perc * SECONDSINDAY));
+ S32Hours hourofday(secondofday);
+ S32Seconds secondofhour(secondofday - hourofday);
+ S32Minutes minutesofhour(secondofhour);
+ bool am_pm(hourofday.value() >= 12);
+
+ if (hourofday.value() < 1)
+ hourofday = S32Hours(12);
+ if (hourofday.value() > 12)
+ hourofday -= S32Hours(12);
+
+ std::string lblminute(((minutesofhour.value() < 10) ? "0" : "") + LLSD(minutesofhour.value()).asString());
+
+
+ getChild<LLUICtrl>(LBL_TIMEOFDAY)->setTextArg("[HH]", LLSD(hourofday.value()).asString());
+ getChild<LLUICtrl>(LBL_TIMEOFDAY)->setTextArg("[MM]", lblminute);
+ getChild<LLUICtrl>(LBL_TIMEOFDAY)->setTextArg("[AP]", std::string(am_pm ? "PM" : "AM"));
+ getChild<LLUICtrl>(LBL_TIMEOFDAY)->setTextArg("[PRC]", LLSD((S32)(100 * perc)).asString());
+
+}
+
+void LLPanelEnvironmentInfo::onIdlePlay(void *data)
+{
+ ((LLPanelEnvironmentInfo *)data)->udpateApparentTimeOfDay();
+}
+
+void LLPanelEnvironmentInfo::onPickerCommitted(LLUUID item_id)
+{
+ LLInventoryItem *itemp = gInventory.getItem(item_id);
+ if (itemp)
+ {
+ LLSettingsVOBase::getSettingsAsset(itemp->getAssetUUID(), [this](LLUUID, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) {
+ if (status)
+ return;
+ onPickerAssetDownloaded(settings);
+ });
+ }
+}
+
+void LLPanelEnvironmentInfo::onEditCommitted(LLSettingsDay::ptr_t newday)
+{
+ if (!newday)
+ {
+ LL_WARNS("ENVPANEL") << "Editor committed an empty day. Do nothing." << LL_ENDL;
+ return;
+ }
+ if (!mCurrentEnvironment)
+ {
+ // Attempting to save mid update?
+ LL_WARNS("ENVPANEL") << "Failed to apply changes from editor! Dirty state: " << mDirtyFlag << " env version: " << mCurEnvVersion << LL_ENDL;
+ return;
+ }
+ size_t newhash(newday->getHash());
+ size_t oldhash((mCurrentEnvironment->mDayCycle) ? mCurrentEnvironment->mDayCycle->getHash() : 0);
+
+ if (newhash != oldhash)
+ {
+ mCurrentEnvironment->mDayCycle = newday;
+ setDirtyFlag(DIRTY_FLAG_DAYCYCLE);
+ refresh();
+ }
+}
+
+void LLPanelEnvironmentInfo::onEnvironmentChanged(LLEnvironment::EnvSelection_t env, S32 new_version)
+{
+ if (new_version < INVALID_PARCEL_ENVIRONMENT_VERSION)
+ {
+ // cleanups and local changes, we are only interested in changes sent by server
+ return;
+ }
+
+ LL_DEBUGS("ENVPANEL") << "Received environment update " << mCurEnvVersion << " " << new_version << LL_ENDL;
+
+ // Environment comes from different sources, from environment update callbacks,
+ // from hovers (causes callbacks on version change) and from personal requests
+ // filter out duplicates and out of order packets by checking parcel environment version.
+
+ if (isRegion())
+ {
+ // Note: region uses same init versions as parcel
+ if (env == LLEnvironment::ENV_REGION
+ // version should be always growing, UNSET_PARCEL_ENVIRONMENT_VERSION is backup case
+ && (mCurEnvVersion < new_version || mCurEnvVersion <= UNSET_PARCEL_ENVIRONMENT_VERSION))
+ {
+ if (new_version >= UNSET_PARCEL_ENVIRONMENT_VERSION)
+ {
+ // 'pending state' to prevent re-request on following onEnvironmentChanged if there will be any
+ mCurEnvVersion = new_version;
+ }
+ mCurrentEnvironment.reset();
+ refreshFromSource();
+ }
+ }
+ else if ((env == LLEnvironment::ENV_PARCEL)
+ && (getParcelId() == LLViewerParcelMgr::instance().getAgentParcelId()))
+ {
+ LLParcel *parcel = getParcel();
+ if (parcel)
+ {
+ // first for parcel own settings, second is for case when parcel uses region settings
+ if (mCurEnvVersion < new_version
+ || (mCurEnvVersion != new_version && new_version == UNSET_PARCEL_ENVIRONMENT_VERSION))
+ {
+ // 'pending state' to prevent re-request on following onEnvironmentChanged if there will be any
+ mCurEnvVersion = new_version;
+ mCurrentEnvironment.reset();
+
+ refreshFromSource();
+ }
+ else if (mCurrentEnvironment)
+ {
+ // update controls
+ refresh();
+ }
+ }
+ }
+}
+
+
+void LLPanelEnvironmentInfo::onPickerAssetDownloaded(LLSettingsBase::ptr_t settings)
+{
+ LLSettingsVODay::buildFromOtherSetting(settings, [this](LLSettingsDay::ptr_t pday)
+ {
+ if (pday)
+ {
+ mCurrentEnvironment->mDayCycle = pday;
+ setDirtyFlag(DIRTY_FLAG_DAYCYCLE);
+ }
+ refresh();
+ });
+}
+
+void LLPanelEnvironmentInfo::onEnvironmentReceived(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo)
+{
+ if (parcel_id != getParcelId())
+ {
+ LL_WARNS("ENVPANEL") << "Have environment for parcel " << parcel_id << " expecting " << getParcelId() << ". Discarding." << LL_ENDL;
+ return;
+ }
+ mCurrentEnvironment = envifo;
+ clearDirtyFlag(DIRTY_FLAG_MASK);
+ if (mCurrentEnvironment->mEnvVersion > INVALID_PARCEL_ENVIRONMENT_VERSION)
+ {
+ // Server provided version, use it
+ mCurEnvVersion = mCurrentEnvironment->mEnvVersion;
+ LL_DEBUGS("ENVPANEL") << " Setting environment version: " << mCurEnvVersion << " for parcel id: " << parcel_id << LL_ENDL;
+ }
+ // Backup: Version was not provided for some reason
+ else
+ {
+ LL_WARNS("ENVPANEL") << " Environment version was not provided for " << parcel_id << ", old env version: " << mCurEnvVersion << LL_ENDL;
+ }
+
+ refresh();
+
+ // todo: we have envifo and parcel env version, should we just setEnvironment() and parcel's property to prevent dupplicate requests?
+}
+
+void LLPanelEnvironmentInfo::_onEnvironmentReceived(LLHandle<LLPanel> that_h, S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envifo)
+{
+ LLPanelEnvironmentInfo *that = (LLPanelEnvironmentInfo *)that_h.get();
+ if (!that)
+ return;
+ that->onEnvironmentReceived(parcel_id, envifo);
+}
+
+LLSettingsDropTarget::LLSettingsDropTarget(const LLSettingsDropTarget::Params& p)
+ : LLView(p), mEnvironmentInfoPanel(NULL), mDndEnabled(false)
+{}
+
+BOOL LLSettingsDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
+{
+ BOOL handled = FALSE;
+
+ if (getParent() && mDndEnabled)
+ {
+ handled = TRUE;
+
+ switch (cargo_type)
+ {
+ case DAD_SETTINGS:
+ {
+ LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
+ if (inv_item && mEnvironmentInfoPanel)
+ {
+ LLUUID item_id = inv_item->getUUID();
+ if (gInventory.getItem(item_id))
+ {
+ *accept = ACCEPT_YES_COPY_SINGLE;
+ if (drop)
+ {
+ mEnvironmentInfoPanel->onPickerCommitted(item_id);
+ }
+ }
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+ break;
+ }
+ default:
+ *accept = ACCEPT_NO;
+ break;
+ }
+ }
+ return handled;
+}