FIRE-36685 - Toolbox Window - Add new notecard button to Content tab

Added new "New Notecard" button to the Build Window's Content tab.
Creates a new notecard directly in the objects content inventory.
New scripts and notecards automatically appear at the top of the content inventory with the new object having renamed automatically enabled.
Added flag to settings to store a backup of inventory flags, which is used to disable popup of new objects appearing in the main inventory as new notecards need to appear in the user inventory before being moved over to the object's content inventory.
This commit is contained in:
minerjr
2026-07-19 05:53:11 -03:00
parent 8911054dc9
commit 8ad2191dfd
10 changed files with 548 additions and 1 deletions
+2
View File
@@ -162,6 +162,7 @@ set(viewer_SOURCE_FILES
fsnearbychatcontrol.cpp
fsnearbychathub.cpp
fsnearbychatvoicemonitor.cpp
fsnewitemctrl.cpp
fspanelblocklist.cpp
fspanelcontactsets.cpp
fspanelface.cpp
@@ -1022,6 +1023,7 @@ set(viewer_HEADER_FILES
fsnearbychatcontrol.h
fsnearbychathub.h
fsnearbychatvoicemonitor.h
fsnewitemctrl.h
fspanelblocklist.h
fspanelcontactsets.h
fspanelface.h
+13
View File
@@ -15156,6 +15156,19 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<!-- <FS:mjr> -->
<key>BackupInventoryFlags</key>
<map>
<key>Comment</key>
<string>Store the flags for Show In/New/Gesture inventory</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<!-- </FS:mjr> -->
<key>ShowObjectUpdates</key>
<map>
<key>Comment</key>
+274
View File
@@ -0,0 +1,274 @@
/**
* @file fsnewitemctrl.cpp
* @brief A singleton controller for handling adding new items to Objects using Build Window's Content tab.
*
* $LicenseInfo:firstyear=2026&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (c) 2026 minerjr @ The Phoenix Firestorm Project, 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
* $/LicenseInfo$
*/
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
#include "fsnewitemctrl.h"
#include "llinventory.h"
#include "llviewerinventory.h"
#include "llselectmgr.h"
#include "llcontrol.h" // gSavedSettings
#include "llinventorymodel.h" // gInventory
#include "llagentdata.h" // gAgentID
extern LLControlGroup gSavedSettings;
extern LLInventoryModel gInventory;
extern LLUUID gAgentID;
FSNewItemCtrl::FSNewItemCtrl() : LLSingleton<FSNewItemCtrl>(),
mState(EAddNewItemState::IDLE),
mItemAssetType(LLAssetType::AT_NONE),
mOriginalItemUUID(),
mNewItemUUID()
{
}
FSNewItemCtrl::~FSNewItemCtrl()
{
// delete Xxx;
}
void FSNewItemCtrl::init()
{
mState = EAddNewItemState::IDLE;
mItemAssetType = LLAssetType::AT_NONE;
mOriginalItemUUID.setNull();
mNewItemUUID.setNull();
}
void FSNewItemCtrl::processStates(LLPanelObjectInventory* panel_object_inv)
{
// Check if the passed in panel object inventory is valid, and if not, return
if (panel_object_inv == nullptr)
{
return;
}
LLFolderView* folders = panel_object_inv->getRootFolder();
// Idle state, just return as there is nothing to process
if (mState == EAddNewItemState::IDLE)
{
return;
}
// Handle the start of the drag and drop the item from avatar inventory to the object's inventory
// wait until the inventory movement has finished before handling the item appearing in the inventory
else if (mState == EAddNewItemState::DND_INV_TO_OBJECT)
{
if (LLViewerObject* objectp = gObjectList.findObject(panel_object_inv->getTaskUUID()))
{
// If the inveotory is not pending and not dirty, then we want to move to the next step.
if (objectp && !objectp->isInventoryPending() && !objectp->isInventoryDirty())
{
mState = EAddNewItemState::DND_INV_TO_OBJECT_DONE;
}
}
}
// Handles when the item appears, will select the new item and set it to rename.
// If the item is able to be opened, it will be opened.
else if (mState == EAddNewItemState::DND_INV_TO_OBJECT_DONE)
{
bool inventory_has_focus = panel_object_inv->hasInventory() && folders && gFocusMgr.childHasKeyboardFocus(folders);
// Restore the show new inventory current settings
restoreInventoryFlags();
panel_object_inv->setFocusRoot(true);
if (!mNewItemUUID.isNull())
{
// Flag that item needs to be renamed, needs to be done once added to the actual folder.
LLFolderViewItem* current_item = panel_object_inv->getItemByID(mNewItemUUID);
if (current_item && folders)
{
// Set the found
folders->setSelection(current_item, true, inventory_has_focus);
// mFolders->requestArrange();
folders->startRenamingSelectedItem();
// If the item is a gesture, notecard, text or script, we need to re-open the item floater to allow floater to
// modify the object content's item and not the one generated in the avatar's inventory.
if (mItemAssetType == LLAssetType::AT_LSL_TEXT || mItemAssetType == LLAssetType::AT_NOTECARD ||
mItemAssetType == LLAssetType::AT_GESTURE || mItemAssetType == LLAssetType::AT_MATERIAL)
{
current_item->openItem();
}
}
}
// Turn off the do action
mState = EAddNewItemState::MOVE_INT_TO_TRASH_START;
}
else if (mState == EAddNewItemState::MOVE_INT_TO_TRASH_START)
{
// Once the object's inventory is done being processed, can switch back to the idle state
if (LLViewerObject* objectp = gObjectList.findObject(panel_object_inv->getTaskUUID()))
{
// If there is no original item (LSL scripts), can go back to normal
if (mOriginalItemUUID.isNull())
{
onRemoveItemDone();
}
// Else if the inveotory is not pending and not dirty, then we want to move to the next step.
else if (objectp && !objectp->isInventoryPending() && !objectp->isInventoryDirty())
{
// Remove the original inventory item and do a callback to set the
// state to the next one once it finishes.
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(FSNewItemCtrl::onRemoveItemDone));
remove_inventory_item(mOriginalItemUUID, cb);
// Set the state to the move iventory to trash, which will spin until the callback is triggered
mState = EAddNewItemState::MOVE_INT_TO_TRASH;
}
}
}
// No need to MOVE_INT_TO_TRASH as it's handled by the onRemoveItemDone callback method.
}
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// static
// Callback method for when an item is removed from the avatar's inventory to reset the internal state
void FSNewItemCtrl::onRemoveItemDone()
{
// Store the pointer to the FSNewItemCtrl as a static value as it is a singleton and
// saves from having to be called all the time.
static FSNewItemCtrl* self = FSNewItemCtrl::getInstance();
if (self)
{
// Set the new item state back to idle
self->setState(FSNewItemCtrl::EAddNewItemState::IDLE);
self->callFinishNewItem();
}
}
// Call the Finish New Item callback method if it is valid.
void FSNewItemCtrl::callFinishNewItem()
{
if (mFinishNewItemCallback)
mFinishNewItemCallback();
}
void FSNewItemCtrl::onCreateInvDone(LLHandle<LLPanel> handle, const LLUUID& new_id, const void_callback_t& cb)
{
gInventory.notifyObservers();
LLPanelContents* panel = (LLPanelContents*)handle.get();
if (panel && new_id.notNull())
{
// The the selected object's root object
const bool children_ok = true;
LLPointer<LLViewerObject> object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok);
if (object && new_id.notNull())
{
// Get the Inventory Item from the new ID passed in
LLViewerInventoryItem* item = gInventory.getItem(new_id);
if (item)
{
// If the item can move to the target object
if (LLToolDragAndDrop::isInventoryDropAcceptable(object, item))
{
// Set the panel to treat the newest item as a new item and needs to perform an action on it.
startDNDInvToObject(item->getUUID(), cb);
// Drag and Drop the new item into the inventory of the object.
LLToolDragAndDrop::dropInventory(object, item, LLToolDragAndDrop::SOURCE_AGENT, gAgentID);
}
}
else
{
LL_WARNS() << "Could not transfer new item with ID: " << new_id << LL_ENDL;
}
}
}
}
void FSNewItemCtrl::startDNDInvToObject(const LLUUID& original_UUID, const void_callback_t& cb)
{
// Store the UUID of the original item drag and dropped by the script
// so once it is finished with, can then next move to the avatar's trash.
mOriginalItemUUID = original_UUID;
// Flag that an action needs to take place on the newest item
mState = EAddNewItemState::DND_INV_TO_OBJECT_START;
// Set the finish new item callback to the one passed in, defaults to null.
mFinishNewItemCallback = cb;
}
bool FSNewItemCtrl::checkAgainstLatestObject(const LLPointer<LLInventoryObject> &obj)
{
// If there is a need to do an action on the item, then
if (mState == EAddNewItemState::DND_INV_TO_OBJECT_START)
{
// This is needed to be able to convert the LLPointer<LLInventoryObject> to an LLInventoryItem*.
// Issue is the existing methods ends up returning a const pointer, which you then cannnot
// act upon or return with a static method call.
LLInventoryObject* current_object = obj;
LLInventoryItem* current_item = dynamic_cast<LLInventoryItem*>(current_object);
// Need to search for the newest item as the new item recieved a new UUID so the one
// from the LLPanelContents.cpp no longer exists.
// Use the CreationDate of the item to determine which is the newer item.
if (current_item && current_item->getCreationDate() > mLatestCreationTime)
{
// Store the latest creation date
mLatestCreationTime = current_item->getCreationDate();
// Store the current items new UUID and action type (for use to determine if the item needs to be opened)
mNewItemUUID = current_item->getUUID();
mItemAssetType = current_item->getActualType();
mLatestCreatedItem = current_item;
// Return true as there was a newer item was found
return true;
}
}
// Return false as there was no newer item found
return false;
}
// Store the show invengory flags and disables them.
// Used to hide the item floaters attached to the new avatar items
// so the user does not edit the wrong items.
void FSNewItemCtrl::saveAndClearInventoryFlags()
{
// Save the show new, in and gesture inventory settings
S32 backup_inventory_flags = 0;
backup_inventory_flags |= S32(gSavedSettings.getBOOL("ShowNewInventory")) * SHOW_NEW_INVENTORY;
backup_inventory_flags |= S32(gSavedSettings.getBOOL("ShowInInventory")) * SHOW_IN_INVENTORY;
backup_inventory_flags |= S32(gSavedSettings.getBOOL("ShowGestureInventory")) * SHOW_GESTURE_INVENTORY;
gSavedSettings.setS32("BackupInventoryFlags", backup_inventory_flags);
// do not pop up preview floaters when creating new and in inventory items.
gSavedSettings.setBOOL("ShowNewInventory", false);
gSavedSettings.setBOOL("ShowInInventory", false);
gSavedSettings.setBOOL("ShowGestureInventory", false);
}
// Restores the Show Inventory settings.xml flags.
void FSNewItemCtrl::restoreInventoryFlags()
{
// Restore the show new inventory current settings
S32 backup_inventory_flags = gSavedSettings.getS32("BackupInventoryFlags");
gSavedSettings.setBOOL("ShowGestureInventory", bool(backup_inventory_flags & SHOW_GESTURE_INVENTORY));
gSavedSettings.setBOOL("ShowNewInventory", bool(backup_inventory_flags & SHOW_NEW_INVENTORY));
gSavedSettings.setBOOL("ShowInInventory", bool(backup_inventory_flags & SHOW_IN_INVENTORY));
}
// </FS:mjr> [FIRE-36685]
+101
View File
@@ -0,0 +1,101 @@
/**
* @file fsnewitemctrl.h
* @brief A singleton controller for handling adding new items to Objects using Build Window's Content tab.
*
* $LicenseInfo:firstyear=2026&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (c) 2026 minerjr @ The Phoenix Firestorm Project, 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
* $/LicenseInfo$
*/
#ifndef FSNEWITEMCTRL_H
#define FSNEWITEMCTRL_H
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
#include "llsingleton.h"
#include "llpanelobjectinventory.h"
class LLPanelContents;
class FSNewItemCtrl : public LLSingleton<FSNewItemCtrl>
{
LLSINGLETON(FSNewItemCtrl);
~FSNewItemCtrl();
public:
enum EAddNewItemState
{
IDLE = 0,
DND_INV_TO_OBJECT_START,
DND_INV_TO_OBJECT,
DND_INV_TO_OBJECT_DONE,
MOVE_INT_TO_TRASH_START,
MOVE_INT_TO_TRASH,
MOVE_INT_TO_TRASH_DONE
};
static const S32 SHOW_NEW_INVENTORY = 1;
static const S32 SHOW_IN_INVENTORY = 2;
static const S32 SHOW_GESTURE_INVENTORY = 4;
typedef std::function<void()> void_callback_t;
typedef std::function<void(LLPanelContents *, const LLUUID &new_id)> panel_contents_callback_t;
void init();
void processStates(LLPanelObjectInventory* panel_object_inv);
static void onRemoveItemDone(); // Callback
void callFinishNewItem();
// Used by the LLPanelContents to let this class to enable rename, sticky sort location
// and open the supported window if need be.
void onCreateInvDone(LLHandle<LLPanel> handle, const LLUUID& new_id, const void_callback_t& cb = nullptr);
void startDNDInvToObject(const LLUUID& original_UUID, const void_callback_t& cb = nullptr);
void saveAndClearInventoryFlags(); // Saves the Show Inventory settings.xml flags and clears therm
void restoreInventoryFlags();// Restores the Show Inventory settings.xml flags.
const LLUUID& getNewItemUUID() const { return mNewItemUUID; }
void setNewItemUUID(const LLUUID &new_uuid) { mNewItemUUID = new_uuid; }
const LLUUID& getOriginalItemUUID() const { return mOriginalItemUUID; }
void setOriginalItemUUID(const LLUUID& new_uuid) { mOriginalItemUUID = new_uuid; }
const LLAssetType::EType getItemAssetType() const { return mItemAssetType; }
void setItemAssetType(LLAssetType::EType new_type) { mItemAssetType = new_type; }
EAddNewItemState getState() const { return mState; }
void setState(const EAddNewItemState new_state) { mState = new_state; }
bool checkState(const EAddNewItemState check_state) const { return mState == check_state; }
bool isStateIdle() const { return mState == EAddNewItemState::IDLE; }
void resetLatestCreationTime() { mLatestCreationTime = 0; }
bool checkAgainstLatestObject(const LLPointer<LLInventoryObject> &obj);
void setFinishNewItemCallback(void_callback_t cb) { mFinishNewItemCallback = cb; }
protected:
EAddNewItemState mState; // Flags if there is a item that needs an action performed on it.
LLAssetType::EType mItemAssetType; // Stores the action type of the new item, used for idenifying the idem.
LLUUID mOriginalItemUUID; // Stores the UUID of the item that was first passed to be transfered. UUID is changed when added to object's inventory
LLUUID mNewItemUUID; // The UUID will change when moved so that cannot be used for tracking which item needs to be acted upon.
time_t mLatestCreationTime; // Stores the latest creation time, used for finding the object with the latest version.
LLInventoryItem* mLatestCreatedItem; // Stores the pointer to the latest item found.
void_callback_t mFinishNewItemCallback; // Function pointer used as a callback for when the new item is finished.
};
// </FS:mjr> [FIRE-36685]
#endif
@@ -31,6 +31,7 @@
#include "llinventorypanel.h"
#include "lltooldraganddrop.h"
#include "llfavoritesbar.h"
#include "fsnewitemctrl.h" // <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
//
// class LLFolderViewModelInventory
@@ -333,6 +334,24 @@ bool LLFolderViewModelItemInventory::filter(LLFolderViewFilter& filter)
bool LLInventorySort::operator()(const LLFolderViewModelItemInventory* const& a, const LLFolderViewModelItemInventory* const& b) const
{
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once.
static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance();
// When new items are created with the Build Widow, want the new item to appear at
// the top of the list so the user can edit the name.
// Stores the UUID of the new item as a static value in the LLPanelObjectInventory.
if (!new_item_ctrl->getNewItemUUID().isNull())
{
if (a->getUUID() == new_item_ctrl->getNewItemUUID())
{
return true;
}
else if (b->getUUID() == new_item_ctrl->getNewItemUUID())
{
return false;
}
}
// </FS:mjr> [FIRE-36685]
// Ignore sort order for landmarks in the Favorites folder.
// In that folder, landmarks should be always sorted as in the Favorites bar. See EXT-719
if (a->getSortGroup() == SG_ITEM
+91
View File
@@ -67,6 +67,7 @@
#include "rlvhandler.h"
#include "rlvlocks.h"
// [/RLVa:KB]
#include "fsnewitemctrl.h" // <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
//
// Imported globals
@@ -89,6 +90,7 @@ bool LLPanelContents::postBuild()
setMouseOpaque(false);
childSetAction("button new script",&LLPanelContents::onClickNewScript, this);
childSetAction("button new notecard", &LLPanelContents::onClickNewNotecard, this); // <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
childSetAction("button permissions",&LLPanelContents::onClickPermissions, this);
childSetAction("btn_reset_scripts", &LLPanelContents::onClickResetScripts, this); // <FS> Script reset in edit floater
childSetAction("button refresh",&LLPanelContents::onClickRefresh, this);
@@ -123,6 +125,13 @@ void LLPanelContents::getState(LLViewerObject *objectp )
{
getChildView("button new script")->setEnabled(false);
getChildView("btn_reset_scripts")->setEnabled(false); // <FS> Script reset in edit floater
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
getChildView("button new notecard")->setEnabled(false);
// Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once.
static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance();
// Want to clear the saved New Item UUID as we may click on another object
new_item_ctrl->setNewItemUUID(LLUUID::null);
// </FS:mjr> [FIRE-36685]
return;
}
@@ -169,6 +178,7 @@ void LLPanelContents::getState(LLViewerObject *objectp )
}
getChildView("button new script")->setEnabled(objectIsOK);
getChildView("button new notecard")->setEnabled(objectIsOK); // <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
getChildView("btn_reset_scripts")->setEnabled(objectIsOK);
// </FS:PP>
@@ -263,6 +273,12 @@ void LLPanelContents::clearContents()
// static
void LLPanelContents::onClickNewScript(void *userdata)
{
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once.
static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance();
// Get the Panel Contents from the userdata void pointer.
LLPanelContents* self = (LLPanelContents*)userdata;
// </FS:mjr> [FIRE-36685]
const bool children_ok = true;
LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok);
if(object)
@@ -289,6 +305,10 @@ void LLPanelContents::onClickNewScript(void *userdata)
{
if (auto custom_script = gInventory.getItem(custom_script_id); custom_script && custom_script->getType() == LLAssetType::AT_LSL_TEXT)
{
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// Flag the new script to also needs to be scrolled to and opened if needed.
new_item_ctrl->startDNDInvToObject(LLUUID::null, std::bind(&LLPanelContents::onFinishCreateItem, self));
// </FS:mjr> [FIRE-36685]
LLToolDragAndDrop::dropScript(object, custom_script, true, LLToolDragAndDrop::SOURCE_AGENT, gAgentID);
return;
}
@@ -308,6 +328,10 @@ void LLPanelContents::onClickNewScript(void *userdata)
PERM_MOVE | LLFloaterPerms::getNextOwnerPerms("Scripts"));
std::string desc;
LLViewerAssetType::generateDescriptionFor(LLAssetType::AT_LSL_TEXT, desc);
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// Flag the new script to also needs to be scrolled to and opened if needed.
new_item_ctrl->startDNDInvToObject(LLUUID::null, std::bind(&LLPanelContents::onFinishCreateItem, self));
// </FS:mjr> [FIRE-36685]
LLPointer<LLViewerInventoryItem> new_item =
new LLViewerInventoryItem(
LLUUID::null,
@@ -355,3 +379,70 @@ void LLPanelContents::onClickRefresh(void *userdata)
LLPanelContents* self = (LLPanelContents*)userdata;
self->refresh();
}
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// static
void LLPanelContents::onClickNewNotecard(void* userdata)
{
// Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once.
static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance();
// Get the Panel Contents from the userdata void pointer.
LLPanelContents* self = (LLPanelContents*)userdata;
// Maintain RLV support for notecard object type being added.
const bool children_ok = true;
LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok);
// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a
if (rlv_handler_t::isEnabled()) // Fallback code [see LLPanelContents::getState()]
{
if (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit()))
{
return; // Disallow creating new scripts in a locked attachment
}
else if ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)))
{
if ((isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()))
return; // .. or in a linkset the avie is sitting on under @unsit=n/@sittp=n
}
}
// [/RLVa:KB]
// Need to disable the new notecard button to prevent spaming the button and causing inventory issues
self->getChildView("button new notecard")->setEnabled(false);
// Need to save the filter first so it is not lost
std::string save_filter = self->mFilterEditor->getText();
// Clear the actual filter
self->mFilterEditor->setText(LLStringExplicit(""));
// Update the filter state
self->onFilterEdit();
// </FS:Ansariel>
// Create the LLSD paramater for the new notecard
LLSD component("notecard");
// Callback handle to allow for moving the new item to the object from the avatar inventory
// Also moves the new item in the users avatar inventory to the trash.
// Will also open up the dialog for Gesture and Notecards in the object's inventory.
LLHandle<LLPanel> handle = self->getHandle();
std::function<void(const LLUUID&)> callback_item_created = [handle](const LLUUID& new_id)
{
// Call the on Create Inventory Done of the new item controller which will kick off next steps
new_item_ctrl->onCreateInvDone(handle, new_id, std::bind(&LLPanelContents::onFinishCreateItem, (LLPanelContents*)handle.get()));
};
// Save and clear the Show Inventroy flags used to prevent the floaters appearing
// when items that have floaters like the Notecard, Gesture, Material and Script
// from opening the temp item in the avatars inventory.
new_item_ctrl->saveAndClearInventoryFlags();
// Create the new item using the menu system in the user's avatar inventory.
// The callback from above will move the item to the object and remove it from the user's inventory after.
menu_create_inventory_item(NULL, LLUUID::null, component, LLUUID::null, callback_item_created);
// Restore the filter
self->mFilterEditor->setText(LLStringExplicit(save_filter));
}
// Callback method for when the item finishes
void LLPanelContents::onFinishCreateItem()
{
getChildView("button new notecard")->setEnabled(true);
}
// </FS:mjr> [FIRE-36685]
+5
View File
@@ -51,8 +51,13 @@ public:
void refresh();
void clearContents();
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
void onClickAddItemToObject(); // Adds the actual item to the object's Content Inventory.
void onFinishCreateItem();
// </FS:mjr> [FIRE-36685]
static void onClickNewScript(void*);
static void onClickNewNotecard(void*); // <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
static void onClickPermissions(void*);
static void onClickResetScripts(void*); // <FS> Script reset in edit floater
static void onClickRefresh(void*);
+26
View File
@@ -73,6 +73,7 @@
#include "rlvlocks.h"
// [/RLVa:KB]
#include "llfloaterproperties.h" // <FS:Ansariel> Keep legacy properties floater
#include "fsnewitemctrl.h" // <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
const LLColor4U DEFAULT_WHITE(255, 255, 255);
#include "tea.h" // <FS:AW opensim currency support>
@@ -1797,6 +1798,12 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li
{
LLUIColor item_color = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once.
static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance();
// Reset the latest creation time, to allow for finding the newest item below.
new_item_ctrl->resetLatestCreationTime();
// </FS:mjr> [FIRE-36685]
// Find all in the first pass
std::vector<obj_folder_pair*> child_categories;
for (const LLPointer<LLInventoryObject>& obj : *inventory)
@@ -1850,6 +1857,10 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li
// </FS:Ansariel>
view = LLUICtrlFactory::create<LLFolderViewItem>(params);
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// Check the current object against the existing newest item
new_item_ctrl->checkAgainstLatestObject(obj);
// </FS:mjr> [FIRE-36685]
}
view->addToFolder(folder);
@@ -1865,6 +1876,15 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li
delete pair;
}
folder->setChildrenInited(true);
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// Switch to the next state if not already done so.
// Check to see if the new item control is in the drag and drop inventory to object start state
if (new_item_ctrl->checkState(FSNewItemCtrl::DND_INV_TO_OBJECT_START))
{
// If so, can move on to the next state
new_item_ctrl->setState(FSNewItemCtrl::DND_INV_TO_OBJECT);
}
// </FS:mjr> [FIRE-36685]
}
void LLPanelObjectInventory::refresh()
@@ -2028,6 +2048,12 @@ void LLPanelObjectInventory::idle(void* user_data)
{
self->updateInventory();
}
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
// Store a static pointer to the singleton FSNewItemCtrl so that it only has to be looked up once.
static FSNewItemCtrl* new_item_ctrl = FSNewItemCtrl::getInstance();
// Process the current state using the current LLPanelObjectInveotory
new_item_ctrl->processStates(self);
// <FS:mjr> [FIRE-36685]
}
void LLPanelObjectInventory::onFocusLost()
+3
View File
@@ -47,6 +47,9 @@ class LLViewerObject;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener
{
// <FS:mjr> [FIRE-36685] - Toolbox Window - Add new notecard button to Content tab
friend class FSNewItemCtrl; // Need to declare FSNewItemCtrl a friend class to access the protected methods(getItemByID())
// </FS:mjr> [FIRE-36685]
public:
struct Params : public LLInitParam::Block<Params, LLPanel::Params>
{
@@ -3689,7 +3689,7 @@ Low ↔ Lwst
width="295">
<button
follows="left|top"
height="35"
height="16"
label="New Script"
label_selected="New Script"
layout="topleft"
@@ -3699,12 +3699,25 @@ Low ↔ Lwst
width="90"
font="DejaVu"
font.size="LSmall" />
<button
follows="left|top"
height="16"
label="New Notecard"
label_selected="New Notecard"
layout="topleft"
left="10"
name="button new notecard"
top_pad="4"
width="90"
font="DejaVu"
font.size="LSmall" />
<button
follows="left|top"
height="35"
label="Permissions"
layout="topleft"
left_pad="5"
top="8"
name="button permissions"
width="80"
font="DejaVu"