diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index fda2fc960bb248e1f972bdde664c22f3f4eab0c0..061470316c9b19f0c2f0b30e69b09ddfce8a6e94 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -296,6 +296,7 @@ set(viewer_SOURCE_FILES llfloatermyscripts.cpp llfloatermyenvironment.cpp llfloaternamedesc.cpp + llfloaternewfeaturenotification.cpp llfloaternewlocalinventory.cpp llfloaternotificationsconsole.cpp llfloaternotificationstabbed.cpp @@ -1019,6 +1020,7 @@ set(viewer_HEADER_FILES llfloatermyscripts.h llfloatermyenvironment.h llfloaternamedesc.h + llfloaternewfeaturenotification.h llfloaternewlocalinventory.h llfloaternotificationsconsole.h llfloaternotificationstabbed.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b72c1e28d236d70d123556a26d667d6e90de1a6b..2ffd2133cbda0250edbe5cc65dae70b2c923a33d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5919,6 +5919,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>LastUIFeatureVersion</key> + <map> + <key>Comment</key> + <string>UI Feature Version number for tracking feature notification between viewer builds</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <string></string> + </map> <key>LastFindPanel</key> <map> <key>Comment</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index dd239f3990f36eeadd3c2b798b9e3e1fa3cb9be0..719c6e824eb9aac7410a028d4aaa281af733c028 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -128,6 +128,11 @@ const F64 CHAT_AGE_FAST_RATE = 3.0; const F32 MIN_FIDGET_TIME = 8.f; // seconds const F32 MAX_FIDGET_TIME = 20.f; // seconds +const S32 UI_FEATURE_VERSION = 1; +// For version 1: 1 - inventory, 2 - gltf +// Will need to change to 3 once either inventory or gltf releases and cause a conflict +const S32 UI_FEATURE_FLAGS = 2; + // The agent instance. LLAgent gAgent; @@ -389,7 +394,7 @@ LLAgent::LLAgent() : mHideGroupTitle(FALSE), mGroupID(), - mInitialized(FALSE), + mInitialized(false), mListener(), mDoubleTapRunTimer(), @@ -469,7 +474,7 @@ LLAgent::LLAgent() : mNextFidgetTime(0.f), mCurrentFidget(0), - mFirstLogin(FALSE), + mFirstLogin(false), mOutfitChosen(FALSE), mCrouch(false), mVoiceConnected(false), @@ -531,7 +536,7 @@ void LLAgent::init() mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AGENT); - mInitialized = TRUE; + mInitialized = true; } //----------------------------------------------------------------------------- @@ -586,6 +591,93 @@ void LLAgent::onAppFocusGained() // } } +void LLAgent::setFirstLogin(bool b) +{ + mFirstLogin = b; + + if (mFirstLogin) + { + // Don't notify new users about new features + if (getFeatureVersion() <= UI_FEATURE_VERSION) + { + setFeatureVersion(UI_FEATURE_VERSION, UI_FEATURE_FLAGS); + } + } +} + +void LLAgent::setFeatureVersion(S32 version, S32 flags) +{ + LLSD updated_version; + updated_version["version"] = version; + updated_version["flags"] = flags; + gSavedSettings.setLLSD("LastUIFeatureVersion", updated_version); +} + +S32 LLAgent::getFeatureVersion() +{ + S32 version; + S32 flags; + getFeatureVersionAndFlags(version, flags); + return version; +} + +void LLAgent::getFeatureVersionAndFlags(S32& version, S32& flags) +{ + version = 0; + flags = 0; + LLSD feature_version = gSavedSettings.getLLSD("LastUIFeatureVersion"); + if (feature_version.isInteger()) + { + version = feature_version.asInteger(); + flags = 1; // inventory flag + } + else if (feature_version.isMap()) + { + version = feature_version["version"]; + flags = feature_version["flags"]; + } + else if (!feature_version.isString() && !feature_version.isUndefined()) + { + // is something newer inside? + version = UI_FEATURE_VERSION; + flags = UI_FEATURE_FLAGS; + } +} + +void LLAgent::showLatestFeatureNotification(const std::string key) +{ + S32 version; + S32 flags; // a single release can have multiple new features + getFeatureVersionAndFlags(version, flags); + if (version <= UI_FEATURE_VERSION && (flags & UI_FEATURE_FLAGS) != UI_FEATURE_FLAGS) + { + S32 flag = 0; + + if (key == "inventory") + { + // Notify user about new thumbnail support + flag = 1; + } + + if (key == "gltf") + { + flag = 2; + } + + if ((flags & flag) == 0) + { + // Need to open on top even if called from onOpen, + // do on idle to make sure it's on top + LLSD floater_key(key); + doOnIdleOneTime([floater_key]() + { + LLFloaterReg::showInstance("new_feature_notification", floater_key); + }); + + setFeatureVersion(UI_FEATURE_VERSION, flags | flag); + } + } +} void LLAgent::ageChat() { diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 5a354a3ef3f246ef93711776d5ca151771bc64ed..26cceaffca4623528a4233c330a0c67189cc99b3 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -117,15 +117,20 @@ class LLAgent final : public LLOldEvents::LLObservable //-------------------------------------------------------------------- public: void onAppFocusGained(); - void setFirstLogin(BOOL b) { mFirstLogin = b; } + void setFirstLogin(bool b); // Return TRUE if the database reported this login as the first for this particular user. - BOOL isFirstLogin() const { return mFirstLogin; } - BOOL isInitialized() const { return mInitialized; } + bool isFirstLogin() const { return mFirstLogin; } + bool isInitialized() const { return mInitialized; } + + void setFeatureVersion(S32 version, S32 flags); + S32 getFeatureVersion(); + void getFeatureVersionAndFlags(S32 &version, S32 &flags); + void showLatestFeatureNotification(const std::string key); public: std::string mMOTD; // Message of the day private: - BOOL mInitialized; - BOOL mFirstLogin; + bool mInitialized; + bool mFirstLogin; std::shared_ptr<LLAgentListener> mListener; //-------------------------------------------------------------------- diff --git a/indra/newview/llfloaternewfeaturenotification.cpp b/indra/newview/llfloaternewfeaturenotification.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e5002496744298a6afdda57d09e95bf958886ae --- /dev/null +++ b/indra/newview/llfloaternewfeaturenotification.cpp @@ -0,0 +1,83 @@ +/** + * @file llfloaternewfeaturenotification.cpp + * @brief LLFloaterNewFeatureNotification class implementation + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, 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 "llfloaternewfeaturenotification.h" + + +LLFloaterNewFeatureNotification::LLFloaterNewFeatureNotification(const LLSD& key) + : LLFloater(key) +{ +} + +LLFloaterNewFeatureNotification::~LLFloaterNewFeatureNotification() +{ +} + +BOOL LLFloaterNewFeatureNotification::postBuild() +{ + setCanDrag(FALSE); + getChild<LLButton>("close_btn")->setCommitCallback(boost::bind(&LLFloaterNewFeatureNotification::onCloseBtn, this)); + + const std::string title_txt = "title_txt"; + const std::string dsc_txt = "description_txt"; + std::string feature = "_" + getKey().asString(); + + getChild<LLUICtrl>(title_txt)->setValue(getString(title_txt + feature)); + getChild<LLUICtrl>(dsc_txt)->setValue(getString(dsc_txt + feature)); + + if (getKey().asString() == "gltf") + { + LLRect rect = getRect(); + // make automatic? + reshape(rect.getWidth() + 90, rect.getHeight() + 45); + } + + return TRUE; +} + +void LLFloaterNewFeatureNotification::onOpen(const LLSD& key) +{ + centerOnScreen(); +} + +void LLFloaterNewFeatureNotification::onCloseBtn() +{ + closeFloater(); +} + +void LLFloaterNewFeatureNotification::centerOnScreen() +{ + LLVector2 window_size = LLUI::getInstance()->getWindowSize(); + centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY]))); + LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent()); + if (parent) + { + parent->bringToFront(this); + } +} + diff --git a/indra/newview/llfloaternewfeaturenotification.h b/indra/newview/llfloaternewfeaturenotification.h new file mode 100644 index 0000000000000000000000000000000000000000..95501451dc51c3f8b9b96051c9fe13d0b4ddb0c6 --- /dev/null +++ b/indra/newview/llfloaternewfeaturenotification.h @@ -0,0 +1,49 @@ +/** + * @file llfloaternewfeaturenotification.h + * @brief LLFloaterNewFeatureNotification class definition + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, 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$ + */ + +#ifndef LL_FLOATER_NEW_FEATURE_NOTOFICATION_H +#define LL_FLOATER_NEW_FEATURE_NOTOFICATION_H + +#include "llfloater.h" + +class LLFloaterNewFeatureNotification: + public LLFloater +{ + friend class LLFloaterReg; +public: + BOOL postBuild() override; + void onOpen(const LLSD& key) override; + +private: + LLFloaterNewFeatureNotification(const LLSD& key); + /*virtual*/ ~LLFloaterNewFeatureNotification(); + + void centerOnScreen(); + + void onCloseBtn(); +}; + +#endif diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 1e4591c8c2041948c24715912064a00065bcd324..d092d16cfc2fb5575590a190129a0add215af37e 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1828,7 +1828,12 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe return false; } + // func.mIsOverride=true is used for the singleton material editor floater + // associated with the build floater. This flag also excludes objects from + // the selection that do not satisfy PERM_MODIFY. + llassert(func.mIsOverride); LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, true /*first applicable*/); + LLViewerObject* selected_object = func.mObject; if (!selected_object) { @@ -1929,7 +1934,7 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe bool LLMaterialEditor::canModifyObjectsMaterial() { - LLSelectedTEGetMatData func(false); + LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions, item_out); @@ -1937,7 +1942,7 @@ bool LLMaterialEditor::canModifyObjectsMaterial() bool LLMaterialEditor::canSaveObjectsMaterial() { - LLSelectedTEGetMatData func(false); + LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item_out); @@ -1945,7 +1950,7 @@ bool LLMaterialEditor::canSaveObjectsMaterial() void LLMaterialEditor::saveObjectsMaterialAs() { - LLSelectedTEGetMatData func(false); + LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item = nullptr; bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index a721000b4ef0c8d2db2886aa8532756267089164..39dba3e3444c75874f91f3e22e0f75bff22fd3d7 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -478,6 +478,15 @@ LLPanelFace::~LLPanelFace() unloadMedia(); } +void LLPanelFace::onVisibilityChange(BOOL new_visibility) +{ + if (new_visibility) + { + gAgent.showLatestFeatureNotification("gltf"); + } + LLPanel::onVisibilityChange(new_visibility); +} + void LLPanelFace::draw() { updateCopyTexButton(); diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index fdb393690322394e24f930099aa2257c43e633f6..a572a39f172c42d4bfe4d024e9d35cfab7ab0be3 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -110,6 +110,7 @@ class LLPanelFace : public LLPanel static void onMaterialOverrideReceived(const LLUUID& object_id, S32 side); + /*virtual*/ void onVisibilityChange(BOOL new_visibility); /*virtual*/ void draw(); LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 0181e0879912b98c817da1512ae963f62de3a363..37451dff1b50bb9339823df01ed0bf3f604f781f 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3738,7 +3738,7 @@ bool process_login_success_response(U32& first_sim_size_x, U32& first_sim_size_y std::string flag = login_flags["ever_logged_in"]; if(!flag.empty()) { - gAgent.setFirstLogin((flag == "N") ? TRUE : FALSE); + gAgent.setFirstLogin(flag == "N"); } /* Flag is currently ignored by the viewer. @@ -3829,7 +3829,7 @@ bool process_login_success_response(U32& first_sim_size_x, U32& first_sim_size_y std::string fake_initial_outfit_name = gSavedSettings.getString("FakeInitialOutfitName"); if (!fake_initial_outfit_name.empty()) { - gAgent.setFirstLogin(TRUE); + gAgent.setFirstLogin(true); sInitialOutfit = fake_initial_outfit_name; if (sInitialOutfitGender.empty()) { diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index d2739e117bccc668c8def21e66c0f07e482bdb1a..685066506be8c3f681a9c2c433bd1399c0570fe1 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -191,11 +191,15 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) // an item. BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask) { + BOOL pick_reflection_probe = gSavedSettings.getBOOL("SelectReflectionProbes"); + // don't pick transparent so users can't "pay" transparent objects mPick = gViewerWindow->pickImmediate(x, y, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ TRUE, - /*BOOL pick_particle*/ TRUE); + /*BOOL pick_particle*/ TRUE, + /*BOOL pick_unselectable*/ TRUE, + pick_reflection_probe); mPick.mKeyMask = mask; // claim not handled so UI focus stays same diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 84f0b8075474a181515712203a24e3788ca8b451..0403135416e6eef23b070405988c06c1c2bee8aa 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -117,6 +117,7 @@ #include "llfloatermyscripts.h" #include "llfloatermyenvironment.h" #include "llfloaternamedesc.h" +#include "llfloaternewfeaturenotification.h" #include "llfloaternewlocalinventory.h" #include "llfloaternotificationsconsole.h" #include "llfloaternotificationstabbed.h" @@ -257,6 +258,7 @@ class LLFloaterOpenHandler : public LLCommandHandler "avatar_picker", "camera", "camera_presets", + "change_item_thumbnail" "classified", "add_landmark", "delete_pref_preset", @@ -275,6 +277,7 @@ class LLFloaterOpenHandler : public LLCommandHandler "message_critical", // Modal!!! Login specific. If this is in use elsewhere, better to create a non modal variant "message_tos", // Modal!!! Login specific. "mute_object_by_name", + "new_feature_notification", "publish_classified", "save_pref_preset", "save_camera_preset", @@ -427,6 +430,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>); LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGetBlockedObjectName>); LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>); + LLFloaterReg::add("new_feature_notification", "floater_new_feature_notification.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNewFeatureNotification>); LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotificationConsole>); diff --git a/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml b/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml new file mode 100644 index 0000000000000000000000000000000000000000..c8726d36b44d2b8e81590561ba4bf31bdfd4594d --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + height="130" + width="300" + layout="topleft" + name="floater_new_feature_notification" + title="NEW FEATURE" + show_title="false" + header_height="0" + bg_opaque_image="Window_NoTitle_Foreground" + bg_alpha_image="Window_NoTitle_Background" + can_resize="false" + can_drag_on_left="false" + can_minimize="false" + can_close="false"> + <floater.string name="title_txt_inventory"> +New inventory features + </floater.string> + <floater.string name="description_txt_inventory"> +You can now add preview images to inventory items and view a folder in its own window. +Learn more in this [https://community.secondlife.com/blogs/entry/13637-new-features-inventory-item-preview-and-single-folder-view/ blogpost] + </floater.string> + <floater.string name="title_txt_gltf"> +New GLTF PBR materials support + </floater.string> + <floater.string name="description_txt_gltf"> +You can now use expanded material support with the ability to import and edit GLTF Physically Based Rendering (PBR) Materials. +In order to support the addition of the GLTF format, some areas in the viewer may appear darker than usual. + +Learn more about [https://wiki.secondlife.com/wiki/PBR_Materials Physically Based Rendering (PBR)] + </floater.string> + <text + type="string" + length="1" + follows="top|left|right" + font="SansSerifLargeBold" + text_color="White" + layout="topleft" + left="10" + height="14" + top="10" + right="-10" + name="title_txt"> +New feature + </text> + <text + type="string" + length="1" + follows="top|left|right|bottom" + text_color="White" + layout="topleft" + left="10" + height="40" + top_pad="14" + right="-10" + word_wrap="true" + name="description_txt"> +Feature description + </text> + <button + follows="bottom|left|right" + layout="topleft" + height="24" + label="Got it!" + left="104" + bottom="-10" + name="close_btn" + width="90"/> +</floater>