Updated drag and drop impl. Uses LLDictionary, and also IDs DnD operations.
This commit is contained in:
@@ -317,139 +317,54 @@ void LLCategoryDropDescendentsObserver::done()
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// This array is used to more easily control what happens when a 3d
|
S32 LLToolDragAndDrop::sOperationId = 0;
|
||||||
// drag and drop event occurs. Since there's an array of drop target
|
|
||||||
// and cargo type, it's implemented as an array of pointers to member
|
LLToolDragAndDrop::DragAndDropEntry::DragAndDropEntry(dragOrDrop3dImpl f_none,
|
||||||
// functions which correctly carry out the actual drop.
|
dragOrDrop3dImpl f_self,
|
||||||
LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT][LLToolDragAndDrop::DT_COUNT] =
|
dragOrDrop3dImpl f_avatar,
|
||||||
|
dragOrDrop3dImpl f_object,
|
||||||
|
dragOrDrop3dImpl f_land) :
|
||||||
|
LLDictionaryEntry("")
|
||||||
{
|
{
|
||||||
// Source: DAD_NONE
|
mFunctions[DT_NONE] = f_none;
|
||||||
|
mFunctions[DT_SELF] = f_self;
|
||||||
|
mFunctions[DT_AVATAR] = f_avatar;
|
||||||
|
mFunctions[DT_OBJECT] = f_object;
|
||||||
|
mFunctions[DT_LAND] = f_land;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::LLDragAndDropDictionary::get(EDragAndDropType dad_type, LLToolDragAndDrop::EDropTarget drop_target)
|
||||||
|
{
|
||||||
|
const DragAndDropEntry *entry = lookup(dad_type);
|
||||||
|
if (entry)
|
||||||
{
|
{
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
return (entry->mFunctions[(U8)drop_target]);
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
}
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
|
return &LLToolDragAndDrop::dad3dNULL;
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
|
}
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND
|
|
||||||
},
|
LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary()
|
||||||
// Source: DAD_TEXTURE
|
{
|
||||||
{
|
// DT_NONE DT_SELF DT_AVATAR DT_OBJECT DT_LAND
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
// |-------------------------------|----------------------------------------------|-----------------------------------------------|---------------------------------------------------|--------------------------------|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
addEntry(DAD_NONE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL));
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
addEntry(DAD_TEXTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dTextureObject, &LLToolDragAndDrop::dad3dNULL));
|
||||||
&LLToolDragAndDrop::dad3dTextureObject, // Dest: DT_OBJECT
|
addEntry(DAD_SOUND, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
addEntry(DAD_CALLINGCARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
|
||||||
},
|
addEntry(DAD_LANDMARK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
|
||||||
// Source: DAD_SOUND
|
addEntry(DAD_SCRIPT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dRezScript, &LLToolDragAndDrop::dad3dNULL));
|
||||||
{
|
addEntry(DAD_CLOTHING, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
addEntry(DAD_OBJECT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dRezAttachmentFromInv, &LLToolDragAndDrop::dad3dGiveInventoryObject, &LLToolDragAndDrop::dad3dRezObjectOnObject, &LLToolDragAndDrop::dad3dRezObjectOnLand));
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
addEntry(DAD_NOTECARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
addEntry(DAD_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearCategory, &LLToolDragAndDrop::dad3dGiveInventoryCategory, &LLToolDragAndDrop::dad3dUpdateInventoryCategory, &LLToolDragAndDrop::dad3dNULL));
|
||||||
&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
|
addEntry(DAD_ROOT_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL));
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
addEntry(DAD_BODYPART, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
|
||||||
},
|
addEntry(DAD_ANIMATION, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
|
||||||
// Source: DAD_CALLINGCARD
|
addEntry(DAD_GESTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dActivateGesture, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
|
||||||
{
|
addEntry(DAD_LINK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL));
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
addEntry(DAD_MESH, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dMeshObject, &LLToolDragAndDrop::dad3dNULL));
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
|
||||||
// <edit>
|
|
||||||
//&LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
|
|
||||||
//&LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
|
|
||||||
// </edit>
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_LANDMARK
|
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_SCRIPT
|
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dRezScript, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_CLOTHING
|
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dWearItem, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_OBJECT
|
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dRezAttachmentFromInv, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventoryObject, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dRezObjectOnObject, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dRezObjectOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_NOTECARD
|
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_CATEGORY
|
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dWearCategory, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventoryCategory, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dUpdateInventoryCategory, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dCategoryOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_ROOT
|
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_BODYPART
|
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dWearItem, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_ANIMATION
|
|
||||||
// TODO: animation on self could play it? edit it?
|
// TODO: animation on self could play it? edit it?
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_GESTURE
|
|
||||||
// TODO: gesture on self could play it? edit it?
|
// TODO: gesture on self could play it? edit it?
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dActivateGesture, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
// Source: DAD_LINK
|
|
||||||
// TODO: gesture on self could play it? edit it?
|
|
||||||
{
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
|
|
||||||
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
|
|
||||||
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LLToolDragAndDrop::LLToolDragAndDrop()
|
LLToolDragAndDrop::LLToolDragAndDrop()
|
||||||
@@ -758,6 +673,12 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
|
|||||||
|
|
||||||
mToolTipMsg.clear();
|
mToolTipMsg.clear();
|
||||||
|
|
||||||
|
// Increment the operation id for every drop
|
||||||
|
if (drop)
|
||||||
|
{
|
||||||
|
sOperationId++;
|
||||||
|
}
|
||||||
|
|
||||||
if(top_view)
|
if(top_view)
|
||||||
{
|
{
|
||||||
handled = TRUE;
|
handled = TRUE;
|
||||||
@@ -886,6 +807,21 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
|
|||||||
|
|
||||||
if ( !handled )
|
if ( !handled )
|
||||||
{
|
{
|
||||||
|
// Disallow drag and drop to 3D from the outbox
|
||||||
|
const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false);
|
||||||
|
if (outbox_id.notNull())
|
||||||
|
{
|
||||||
|
for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++)
|
||||||
|
{
|
||||||
|
if (gInventory.isObjectDescendentOf(mCargoIDs[item_index], outbox_id))
|
||||||
|
{
|
||||||
|
*acceptance = ACCEPT_NO;
|
||||||
|
mToolTipMsg = LLTrans::getString("TooltipOutboxDragToWorld");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dragOrDrop3D( x, y, mask, drop, acceptance );
|
dragOrDrop3D( x, y, mask, drop, acceptance );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -896,7 +832,7 @@ void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAccep
|
|||||||
if (mDrop)
|
if (mDrop)
|
||||||
{
|
{
|
||||||
// don't allow drag and drop onto transparent objects
|
// don't allow drag and drop onto transparent objects
|
||||||
pickCallback(gViewerWindow->pickImmediate(x, y, FALSE));
|
pick(gViewerWindow->pickImmediate(x, y, FALSE));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -908,35 +844,42 @@ void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAccep
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LLToolDragAndDrop::pickCallback(const LLPickInfo& pick_info)
|
void LLToolDragAndDrop::pickCallback(const LLPickInfo& pick_info)
|
||||||
|
{
|
||||||
|
if (getInstance() != NULL)
|
||||||
|
{
|
||||||
|
getInstance()->pick(pick_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLToolDragAndDrop::pick(const LLPickInfo& pick_info)
|
||||||
{
|
{
|
||||||
EDropTarget target = DT_NONE;
|
EDropTarget target = DT_NONE;
|
||||||
S32 hit_face = -1;
|
S32 hit_face = -1;
|
||||||
|
|
||||||
LLViewerObject* hit_obj = pick_info.getObject();
|
LLViewerObject* hit_obj = pick_info.getObject();
|
||||||
LLSelectMgr::getInstance()->unhighlightAll();
|
LLSelectMgr::getInstance()->unhighlightAll();
|
||||||
|
bool highlight_object = false;
|
||||||
// Treat attachments as part of the avatar they are attached to.
|
// Treat attachments as part of the avatar they are attached to.
|
||||||
if (hit_obj)
|
if (hit_obj != NULL)
|
||||||
{
|
{
|
||||||
// don't allow drag and drop on grass, trees, etc.
|
// don't allow drag and drop on grass, trees, etc.
|
||||||
if(pick_info.mPickType == LLPickInfo::PICK_FLORA)
|
if (pick_info.mPickType == LLPickInfo::PICK_FLORA)
|
||||||
{
|
{
|
||||||
LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_NO;
|
mCursor = UI_CURSOR_NO;
|
||||||
gViewerWindow->getWindow()->setCursor( LLToolDragAndDrop::getInstance()->mCursor );
|
gViewerWindow->getWindow()->setCursor( mCursor );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hit_obj->isAttachment() && !hit_obj->isHUDAttachment())
|
if (hit_obj->isAttachment() && !hit_obj->isHUDAttachment())
|
||||||
{
|
{
|
||||||
LLVOAvatar* avatar = LLVOAvatar::findAvatarFromAttachment( hit_obj );
|
LLVOAvatar* avatar = LLVOAvatar::findAvatarFromAttachment( hit_obj );
|
||||||
if( !avatar )
|
if (!avatar)
|
||||||
{
|
{
|
||||||
LLToolDragAndDrop::getInstance()->mLastAccept = ACCEPT_NO;
|
mLastAccept = ACCEPT_NO;
|
||||||
LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_NO;
|
mCursor = UI_CURSOR_NO;
|
||||||
gViewerWindow->getWindow()->setCursor( LLToolDragAndDrop::getInstance()->mCursor );
|
gViewerWindow->getWindow()->setCursor( mCursor );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hit_obj = avatar;
|
hit_obj = avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -957,16 +900,7 @@ void LLToolDragAndDrop::pickCallback(const LLPickInfo& pick_info)
|
|||||||
{
|
{
|
||||||
target = DT_OBJECT;
|
target = DT_OBJECT;
|
||||||
hit_face = pick_info.mObjectFace;
|
hit_face = pick_info.mObjectFace;
|
||||||
// if any item being dragged will be applied to the object under our cursor
|
highlight_object = true;
|
||||||
// highlight that object
|
|
||||||
for (S32 i = 0; i < (S32)LLToolDragAndDrop::getInstance()->mCargoIDs.size(); i++)
|
|
||||||
{
|
|
||||||
if (LLToolDragAndDrop::getInstance()->mCargoTypes[i] != DAD_OBJECT || (pick_info.mKeyMask & MASK_CONTROL))
|
|
||||||
{
|
|
||||||
LLSelectMgr::getInstance()->highlightObjectAndFamily(hit_obj);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(pick_info.mPickType == LLPickInfo::PICK_LAND)
|
else if(pick_info.mPickType == LLPickInfo::PICK_LAND)
|
||||||
@@ -975,49 +909,61 @@ void LLToolDragAndDrop::pickCallback(const LLPickInfo& pick_info)
|
|||||||
hit_face = -1;
|
hit_face = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLToolDragAndDrop::getInstance()->mLastAccept = ACCEPT_YES_MULTI;
|
mLastAccept = ACCEPT_YES_MULTI;
|
||||||
|
|
||||||
for (LLToolDragAndDrop::getInstance()->mCurItemIndex = 0; LLToolDragAndDrop::getInstance()->mCurItemIndex < (S32)LLToolDragAndDrop::getInstance()->mCargoIDs.size();
|
for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
|
||||||
LLToolDragAndDrop::getInstance()->mCurItemIndex++)
|
|
||||||
{
|
{
|
||||||
|
const S32 item_index = mCurItemIndex;
|
||||||
|
const EDragAndDropType dad_type = mCargoTypes[item_index];
|
||||||
// Call the right implementation function
|
// Call the right implementation function
|
||||||
LLToolDragAndDrop::getInstance()->mLastAccept = (EAcceptance)llmin(
|
mLastAccept = (EAcceptance)llmin(
|
||||||
(U32)LLToolDragAndDrop::getInstance()->mLastAccept,
|
(U32)mLastAccept,
|
||||||
(U32)callMemberFunction((*LLToolDragAndDrop::getInstance()),
|
(U32)callMemberFunction(*this,
|
||||||
LLToolDragAndDrop::getInstance()->sDragAndDrop3d[LLToolDragAndDrop::getInstance()->mCargoTypes[LLToolDragAndDrop::getInstance()->mCurItemIndex]][target])
|
LLDragAndDropDictionary::instance().get(dad_type, target))
|
||||||
(hit_obj, hit_face, pick_info.mKeyMask, FALSE));
|
(hit_obj, hit_face, pick_info.mKeyMask, FALSE));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LLToolDragAndDrop::getInstance()->mDrop &&
|
if (mDrop && ((U32)mLastAccept >= ACCEPT_YES_COPY_SINGLE))
|
||||||
(U32)LLToolDragAndDrop::getInstance()->mLastAccept >= ACCEPT_YES_COPY_SINGLE)
|
|
||||||
{
|
{
|
||||||
// if target allows multi-drop or there is only one item being dropped, go ahead
|
// if target allows multi-drop or there is only one item being dropped, go ahead
|
||||||
if (LLToolDragAndDrop::getInstance()->mLastAccept >= ACCEPT_YES_COPY_MULTI ||
|
if ((mLastAccept >= ACCEPT_YES_COPY_MULTI) || (mCargoIDs.size() == 1))
|
||||||
LLToolDragAndDrop::getInstance()->mCargoIDs.size() == 1)
|
|
||||||
{
|
{
|
||||||
// Target accepts multi, or cargo is a single-drop
|
// Target accepts multi, or cargo is a single-drop
|
||||||
for (LLToolDragAndDrop::getInstance()->mCurItemIndex = 0;
|
for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
|
||||||
LLToolDragAndDrop::getInstance()->mCurItemIndex < (S32)LLToolDragAndDrop::getInstance()->mCargoIDs.size();
|
|
||||||
LLToolDragAndDrop::getInstance()->mCurItemIndex++)
|
|
||||||
{
|
{
|
||||||
|
const S32 item_index = mCurItemIndex;
|
||||||
|
const EDragAndDropType dad_type = mCargoTypes[item_index];
|
||||||
// Call the right implementation function
|
// Call the right implementation function
|
||||||
(U32)callMemberFunction((*LLToolDragAndDrop::getInstance()),
|
(U32)callMemberFunction(*this,
|
||||||
LLToolDragAndDrop::getInstance()->sDragAndDrop3d[LLToolDragAndDrop::getInstance()->mCargoTypes[LLToolDragAndDrop::getInstance()->mCurItemIndex]][target])
|
LLDragAndDropDictionary::instance().get(dad_type, target))
|
||||||
(hit_obj, hit_face, pick_info.mKeyMask, TRUE);
|
(hit_obj, hit_face, pick_info.mKeyMask, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Target does not accept multi, but cargo is multi
|
// Target does not accept multi, but cargo is multi
|
||||||
LLToolDragAndDrop::getInstance()->mLastAccept = ACCEPT_NO;
|
mLastAccept = ACCEPT_NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ECursorType cursor = LLToolDragAndDrop::getInstance()->acceptanceToCursor( LLToolDragAndDrop::getInstance()->mLastAccept );
|
if (highlight_object && mLastAccept > ACCEPT_NO_LOCKED)
|
||||||
|
{
|
||||||
|
// if any item being dragged will be applied to the object under our cursor
|
||||||
|
// highlight that object
|
||||||
|
for (S32 i = 0; i < (S32)mCargoIDs.size(); i++)
|
||||||
|
{
|
||||||
|
if (mCargoTypes[i] != DAD_OBJECT || (pick_info.mKeyMask & MASK_CONTROL))
|
||||||
|
{
|
||||||
|
LLSelectMgr::getInstance()->highlightObjectAndFamily(hit_obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ECursorType cursor = acceptanceToCursor( mLastAccept );
|
||||||
gViewerWindow->getWindow()->setCursor( cursor );
|
gViewerWindow->getWindow()->setCursor( cursor );
|
||||||
|
|
||||||
LLToolDragAndDrop::getInstance()->mLastHitPos = pick_info.mPosGlobal;
|
mLastHitPos = pick_info.mPosGlobal;
|
||||||
LLToolDragAndDrop::getInstance()->mLastCameraPos = gAgentCamera.getCameraPositionGlobal();
|
mLastCameraPos = gAgentCamera.getCameraPositionGlobal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@@ -1143,6 +1089,31 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj,
|
|||||||
hit_obj->sendTEUpdate();
|
hit_obj->sendTEUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj,
|
||||||
|
LLInventoryItem* item,
|
||||||
|
LLToolDragAndDrop::ESource source,
|
||||||
|
const LLUUID& src_id)
|
||||||
|
{
|
||||||
|
if (!item)
|
||||||
|
{
|
||||||
|
llwarns << "no inventory item." << llendl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LLUUID asset_id = item->getAssetUUID();
|
||||||
|
BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
|
||||||
|
if(!success)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLSculptParams sculpt_params;
|
||||||
|
sculpt_params.setSculptTexture(asset_id);
|
||||||
|
sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH);
|
||||||
|
hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
|
||||||
|
|
||||||
|
dialog_refresh_all();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item)
|
void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item)
|
||||||
{
|
{
|
||||||
@@ -1557,6 +1528,10 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
|
|||||||
worn = TRUE;
|
worn = TRUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LLAssetType::AT_CALLINGCARD:
|
||||||
|
// Calling Cards in object are disabled for now
|
||||||
|
// because of incomplete LSL support. See STORM-1117.
|
||||||
|
return ACCEPT_NO;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1961,10 +1936,10 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript(
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
EAcceptance LLToolDragAndDrop::dad3dTextureObject(
|
EAcceptance LLToolDragAndDrop::dad3dApplyToObject(
|
||||||
LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
|
LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type)
|
||||||
{
|
{
|
||||||
lldebugs << "LLToolDragAndDrop::dad3dTextureObject()" << llendl;
|
lldebugs << "LLToolDragAndDrop::dad3dApplyToObject()" << llendl;
|
||||||
|
|
||||||
// <edit>
|
// <edit>
|
||||||
// Fuck this
|
// Fuck this
|
||||||
@@ -2005,15 +1980,25 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject(
|
|||||||
|
|
||||||
if(drop && (ACCEPT_YES_SINGLE <= rv))
|
if(drop && (ACCEPT_YES_SINGLE <= rv))
|
||||||
{
|
{
|
||||||
if((mask & MASK_SHIFT))
|
if (cargo_type == DAD_TEXTURE)
|
||||||
{
|
{
|
||||||
dropTextureAllFaces(obj, item, mSource, mSourceID);
|
if((mask & MASK_SHIFT))
|
||||||
|
{
|
||||||
|
dropTextureAllFaces(obj, item, mSource, mSourceID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dropTextureOneFace(obj, face, item, mSource, mSourceID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cargo_type == DAD_MESH)
|
||||||
|
{
|
||||||
|
dropMesh(obj, item, mSource, mSourceID);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dropTextureOneFace(obj, face, item, mSource, mSourceID);
|
llwarns << "unsupported asset type" << llendl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// VEFFECT: SetTexture
|
// VEFFECT: SetTexture
|
||||||
LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
|
LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
|
||||||
@@ -2026,6 +2011,21 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject(
|
|||||||
// enable multi-drop, although last texture will win
|
// enable multi-drop, although last texture will win
|
||||||
return ACCEPT_YES_MULTI;
|
return ACCEPT_YES_MULTI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EAcceptance LLToolDragAndDrop::dad3dTextureObject(
|
||||||
|
LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
|
||||||
|
{
|
||||||
|
return dad3dApplyToObject(obj, face, mask, drop, DAD_TEXTURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
EAcceptance LLToolDragAndDrop::dad3dMeshObject(
|
||||||
|
LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
|
||||||
|
{
|
||||||
|
return dad3dApplyToObject(obj, face, mask, drop, DAD_MESH);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
EAcceptance LLToolDragAndDrop::dad3dTextureSelf(
|
EAcceptance LLToolDragAndDrop::dad3dTextureSelf(
|
||||||
LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
|
LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
|
||||||
@@ -2169,6 +2169,12 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
|
|||||||
return ACCEPT_NO;
|
return ACCEPT_NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
|
||||||
|
if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id))
|
||||||
|
{
|
||||||
|
return ACCEPT_NO;
|
||||||
|
}
|
||||||
|
|
||||||
if(drop)
|
if(drop)
|
||||||
{
|
{
|
||||||
BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
|
BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
|
||||||
@@ -2590,11 +2596,10 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory(
|
|||||||
}
|
}
|
||||||
else if(mSource == SOURCE_NOTECARD)
|
else if(mSource == SOURCE_NOTECARD)
|
||||||
{
|
{
|
||||||
LLPreviewNotecard* card;
|
LLPreviewNotecard* preview = dynamic_cast<LLPreviewNotecard*>(LLPreview::find(mSourceID));
|
||||||
card = (LLPreviewNotecard*)LLPreview::find(mSourceID);
|
if(preview)
|
||||||
if(card)
|
|
||||||
{
|
{
|
||||||
item = (LLViewerInventoryItem*)card->getDragItem();
|
item = (LLViewerInventoryItem*)preview->getDragItem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(item) return item;
|
if(item) return item;
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public:
|
|||||||
const LLUUID& source_id = LLUUID::null,
|
const LLUUID& source_id = LLUUID::null,
|
||||||
const LLUUID& object_id = LLUUID::null);
|
const LLUUID& object_id = LLUUID::null);
|
||||||
void beginMultiDrag(const std::vector<EDragAndDropType> types,
|
void beginMultiDrag(const std::vector<EDragAndDropType> types,
|
||||||
const std::vector<LLUUID>& cargo_ids,
|
const uuid_vec_t& cargo_ids,
|
||||||
ESource source,
|
ESource source,
|
||||||
const LLUUID& source_id = LLUUID::null);
|
const LLUUID& source_id = LLUUID::null);
|
||||||
void endDrag();
|
void endDrag();
|
||||||
@@ -86,6 +86,9 @@ public:
|
|||||||
const LLUUID& getSourceID() const { return mSourceID; }
|
const LLUUID& getSourceID() const { return mSourceID; }
|
||||||
const LLUUID& getObjectID() const { return mObjectID; }
|
const LLUUID& getObjectID() const { return mObjectID; }
|
||||||
EAcceptance getLastAccept() { return mLastAccept; }
|
EAcceptance getLastAccept() { return mLastAccept; }
|
||||||
|
|
||||||
|
uuid_vec_t::size_type getCargoIDsCount() const { return mCargoIDs.size(); }
|
||||||
|
static S32 getOperationId() { return sOperationId; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum EDropTarget
|
enum EDropTarget
|
||||||
@@ -109,6 +112,7 @@ protected:
|
|||||||
void dragOrDrop3D(S32 x, S32 y, MASK mask, BOOL drop,
|
void dragOrDrop3D(S32 x, S32 y, MASK mask, BOOL drop,
|
||||||
EAcceptance* acceptance);
|
EAcceptance* acceptance);
|
||||||
static void pickCallback(const LLPickInfo& pick_info);
|
static void pickCallback(const LLPickInfo& pick_info);
|
||||||
|
void pick(const LLPickInfo& pick_info);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -117,11 +121,13 @@ protected:
|
|||||||
|
|
||||||
std::vector<EDragAndDropType> mCargoTypes;
|
std::vector<EDragAndDropType> mCargoTypes;
|
||||||
//void* mCargoData;
|
//void* mCargoData;
|
||||||
std::vector<LLUUID> mCargoIDs;
|
uuid_vec_t mCargoIDs;
|
||||||
ESource mSource;
|
ESource mSource;
|
||||||
LLUUID mSourceID;
|
LLUUID mSourceID;
|
||||||
LLUUID mObjectID;
|
LLUUID mObjectID;
|
||||||
|
|
||||||
|
static S32 sOperationId;
|
||||||
|
|
||||||
LLVector3d mLastCameraPos;
|
LLVector3d mLastCameraPos;
|
||||||
LLVector3d mLastHitPos;
|
LLVector3d mLastHitPos;
|
||||||
|
|
||||||
@@ -131,10 +137,6 @@ protected:
|
|||||||
S32 mCurItemIndex;
|
S32 mCurItemIndex;
|
||||||
std::string mToolTipMsg;
|
std::string mToolTipMsg;
|
||||||
|
|
||||||
// array of pointers to functions that implement the logic to
|
|
||||||
// dragging and dropping into the simulator.
|
|
||||||
static dragOrDrop3dImpl sDragAndDrop3d[DAD_COUNT][DT_COUNT];
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// 3d drop functions. these call down into the static functions
|
// 3d drop functions. these call down into the static functions
|
||||||
// named drop<ThingToDrop> if drop is TRUE and permissions allow
|
// named drop<ThingToDrop> if drop is TRUE and permissions allow
|
||||||
@@ -148,6 +150,8 @@ protected:
|
|||||||
MASK mask, BOOL drop);
|
MASK mask, BOOL drop);
|
||||||
EAcceptance dad3dTextureObject(LLViewerObject* obj, S32 face,
|
EAcceptance dad3dTextureObject(LLViewerObject* obj, S32 face,
|
||||||
MASK mask, BOOL drop);
|
MASK mask, BOOL drop);
|
||||||
|
EAcceptance dad3dMeshObject(LLViewerObject* obj, S32 face,
|
||||||
|
MASK mask, BOOL drop);
|
||||||
// EAcceptance dad3dTextureSelf(LLViewerObject* obj, S32 face,
|
// EAcceptance dad3dTextureSelf(LLViewerObject* obj, S32 face,
|
||||||
// MASK mask, BOOL drop);
|
// MASK mask, BOOL drop);
|
||||||
EAcceptance dad3dWearItem(LLViewerObject* obj, S32 face,
|
EAcceptance dad3dWearItem(LLViewerObject* obj, S32 face,
|
||||||
@@ -179,6 +183,11 @@ protected:
|
|||||||
EAcceptance dad3dActivateGesture(LLViewerObject *obj, S32 face,
|
EAcceptance dad3dActivateGesture(LLViewerObject *obj, S32 face,
|
||||||
MASK mask, BOOL drop);
|
MASK mask, BOOL drop);
|
||||||
|
|
||||||
|
// helper called by methods above to handle "application" of an item
|
||||||
|
// to an object (texture applied to face, mesh applied to shape, etc.)
|
||||||
|
EAcceptance dad3dApplyToObject(LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type);
|
||||||
|
|
||||||
|
|
||||||
// set the LLToolDragAndDrop's cursor based on the given acceptance
|
// set the LLToolDragAndDrop's cursor based on the given acceptance
|
||||||
ECursorType acceptanceToCursor( EAcceptance acceptance );
|
ECursorType acceptanceToCursor( EAcceptance acceptance );
|
||||||
|
|
||||||
@@ -212,7 +221,6 @@ public:
|
|||||||
// helper functions
|
// helper functions
|
||||||
static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); }
|
static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); }
|
||||||
|
|
||||||
|
|
||||||
BOOL dadUpdateInventory(LLViewerObject* obj, BOOL drop);
|
BOOL dadUpdateInventory(LLViewerObject* obj, BOOL drop);
|
||||||
BOOL dadUpdateInventoryCategory(LLViewerObject* obj, BOOL drop);
|
BOOL dadUpdateInventoryCategory(LLViewerObject* obj, BOOL drop);
|
||||||
|
|
||||||
@@ -230,6 +238,11 @@ public:
|
|||||||
LLInventoryItem* item,
|
LLInventoryItem* item,
|
||||||
ESource source,
|
ESource source,
|
||||||
const LLUUID& src_id);
|
const LLUUID& src_id);
|
||||||
|
static void dropMesh(LLViewerObject* hit_obj,
|
||||||
|
LLInventoryItem* item,
|
||||||
|
ESource source,
|
||||||
|
const LLUUID& src_id);
|
||||||
|
|
||||||
//static void dropTextureOneFaceAvatar(LLVOAvatar* avatar,S32 hit_face,
|
//static void dropTextureOneFaceAvatar(LLVOAvatar* avatar,S32 hit_face,
|
||||||
// LLInventoryItem* item)
|
// LLInventoryItem* item)
|
||||||
|
|
||||||
@@ -242,6 +255,25 @@ public:
|
|||||||
EDragAndDropType cargo_type,
|
EDragAndDropType cargo_type,
|
||||||
void* cargo_data,
|
void* cargo_data,
|
||||||
EAcceptance* accept);
|
EAcceptance* accept);
|
||||||
|
|
||||||
|
// Classes used for determining 3d drag and drop types.
|
||||||
|
private:
|
||||||
|
struct DragAndDropEntry : public LLDictionaryEntry
|
||||||
|
{
|
||||||
|
DragAndDropEntry(dragOrDrop3dImpl f_none,
|
||||||
|
dragOrDrop3dImpl f_self,
|
||||||
|
dragOrDrop3dImpl f_avatar,
|
||||||
|
dragOrDrop3dImpl f_object,
|
||||||
|
dragOrDrop3dImpl f_land);
|
||||||
|
dragOrDrop3dImpl mFunctions[DT_COUNT];
|
||||||
|
};
|
||||||
|
class LLDragAndDropDictionary : public LLSingleton<LLDragAndDropDictionary>,
|
||||||
|
public LLDictionary<EDragAndDropType, DragAndDropEntry>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LLDragAndDropDictionary();
|
||||||
|
dragOrDrop3dImpl get(EDragAndDropType dad_type, EDropTarget drop_target);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// utility functions
|
// utility functions
|
||||||
|
|||||||
Reference in New Issue
Block a user