summaryrefslogtreecommitdiff
path: root/indra/newview/lltexturectrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/lltexturectrl.cpp')
-rw-r--r--indra/newview/lltexturectrl.cpp1368
1 files changed, 1368 insertions, 0 deletions
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
new file mode 100644
index 0000000000..8a098f4482
--- /dev/null
+++ b/indra/newview/lltexturectrl.cpp
@@ -0,0 +1,1368 @@
+/**
+ * @file lltexturectrl.cpp
+ * @author Richard Nelson, James Cook
+ * @brief LLTextureCtrl class implementation including related functions
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltexturectrl.h"
+
+#include "llagent.h"
+#include "llviewerimagelist.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "llbutton.h"
+#include "lldraghandle.h"
+#include "llfocusmgr.h"
+#include "llviewerimage.h"
+#include "llfolderview.h"
+#include "llinventory.h"
+#include "llinventorymodel.h"
+#include "llinventoryview.h"
+#include "lllineeditor.h"
+#include "llui.h"
+#include "llviewerinventory.h"
+#include "llpermissions.h"
+#include "llsaleinfo.h"
+#include "llassetstorage.h"
+#include "lltextbox.h"
+#include "llresizehandle.h"
+#include "llscrollcontainer.h"
+#include "lltoolmgr.h"
+#include "lltoolpipette.h"
+
+#include "lltool.h"
+#include "llviewerwindow.h"
+#include "llviewerobject.h"
+#include "llviewercontrol.h"
+#include "llglheaders.h"
+#include "llvieweruictrlfactory.h"
+
+
+static const S32 CLOSE_BTN_WIDTH = 100;
+const S32 PIPETTE_BTN_WIDTH = 32;
+static const S32 HPAD = 4;
+static const S32 VPAD = 4;
+static const S32 LINE = 16;
+static const S32 SMALL_BTN_WIDTH = 64;
+static const S32 TEX_PICKER_MIN_WIDTH =
+ (HPAD +
+ CLOSE_BTN_WIDTH +
+ HPAD +
+ CLOSE_BTN_WIDTH +
+ HPAD +
+ SMALL_BTN_WIDTH +
+ HPAD +
+ SMALL_BTN_WIDTH +
+ HPAD +
+ 30 +
+ RESIZE_HANDLE_WIDTH * 2);
+static const S32 CLEAR_BTN_WIDTH = 50;
+static const S32 TEX_PICKER_MIN_HEIGHT = 290;
+static const S32 FOOTER_HEIGHT = 100;
+static const S32 BORDER_PAD = HPAD;
+static const S32 TEXTURE_INVENTORY_PADDING = 30;
+static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
+static const F32 CONTEXT_CONE_OUT_ALPHA = 0.35f;
+
+
+//static const char CURRENT_IMAGE_NAME[] = "Current Texture";
+//static const char WHITE_IMAGE_NAME[] = "Blank Texture";
+//static const char NO_IMAGE_NAME[] = "None";
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// LLFloaterTexturePicker
+
+class LLFloaterTexturePicker : public LLFloater
+{
+public:
+ LLFloaterTexturePicker(
+ LLTextureCtrl* owner,
+ const LLRect& rect,
+ const std::string& label,
+ PermissionMask immediate_filter_perm_mask,
+ PermissionMask non_immediate_filter_perm_mask,
+ BOOL can_apply_immediately);
+ virtual ~LLFloaterTexturePicker();
+
+ // LLView overrides
+ virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,
+ BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
+ EAcceptance *accept,
+ LLString& tooltip_msg);
+ virtual void draw();
+
+ // LLFloater overrides
+ virtual void onClose(bool app_quitting);
+
+ // New functions
+ void setImageID( const LLUUID& image_asset_id);
+ void updateImageStats();
+ const LLUUID& getAssetID() { return mImageAssetID; }
+ const LLUUID& findItemID(const LLUUID& asset_id, BOOL copyable_only);
+ void setCanApplyImmediately(BOOL b);
+
+ void setDirty( BOOL b ) { mIsDirty = b; }
+ BOOL isDirty() { return mIsDirty; }
+ void setActive( BOOL active );
+
+ LLTextureCtrl* getOwner() const { return mOwner; }
+ void setOwner(LLTextureCtrl* owner) { mOwner = owner; }
+
+ void stopUsingPipette();
+ PermissionMask getFilterPermMask();
+ void updateFilterPermMask();
+ void commitIfImmediateSet();
+
+ static void onBtnSetToDefault( void* userdata );
+ static void onBtnSelect( void* userdata );
+ static void onBtnCancel( void* userdata );
+ static void onBtnPipette( void* userdata );
+ //static void onBtnRevert( void* userdata );
+ static void onBtnWhite( void* userdata );
+ static void onBtnNone( void* userdata );
+ static void onBtnClear( void* userdata );
+ static void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action, void* data);
+ static void onShowFolders(LLUICtrl* ctrl, void* userdata);
+ static void onApplyImmediateCheck(LLUICtrl* ctrl, void* userdata);
+ static void onSearchEdit(const LLString& search_string, void* user_data );
+ static void onTextureSelect( const LLTextureEntry& te, void *data );
+
+protected:
+ LLPointer<LLViewerImage> mTexturep;
+ LLTextureCtrl* mOwner;
+
+ LLUUID mImageAssetID; // Currently selected texture
+
+ LLUUID mWhiteImageAssetID;
+ LLUUID mSpecialCurrentImageAssetID; // Used when the asset id has no corresponding texture in the user's inventory.
+ LLUUID mOriginalImageAssetID;
+
+ LLTextBox* mTentativeLabel;
+ LLTextBox* mResolutionLabel;
+
+ LLString mPendingName;
+ BOOL mIsDirty;
+ BOOL mActive;
+
+ LLSearchEditor* mSearchEdit;
+ LLInventoryPanel* mInventoryPanel;
+ PermissionMask mImmediateFilterPermMask;
+ PermissionMask mNonImmediateFilterPermMask;
+ BOOL mCanApplyImmediately;
+ BOOL mNoCopyTextureSelected;
+ F32 mContextConeOpacity;
+};
+
+LLFloaterTexturePicker::LLFloaterTexturePicker(
+ LLTextureCtrl* owner,
+ const LLRect& rect,
+ const std::string& label,
+ PermissionMask immediate_filter_perm_mask,
+ PermissionMask non_immediate_filter_perm_mask,
+ BOOL can_apply_immediately)
+ :
+ LLFloater( "texture picker",
+ rect,
+ LLString( "Pick: " ) + label,
+ TRUE,
+ TEX_PICKER_MIN_WIDTH, TEX_PICKER_MIN_HEIGHT ),
+ mOwner( owner ),
+ mImageAssetID( owner->getImageAssetID() ),
+ mWhiteImageAssetID( gSavedSettings.getString( "UIImgWhiteUUID" ) ),
+ mOriginalImageAssetID(owner->getImageAssetID()),
+ mTentativeLabel(NULL),
+ mResolutionLabel(NULL),
+ mIsDirty( FALSE ),
+ mActive( TRUE ),
+ mSearchEdit(NULL),
+ mImmediateFilterPermMask(immediate_filter_perm_mask),
+ mNonImmediateFilterPermMask(non_immediate_filter_perm_mask),
+ mContextConeOpacity(0.f)
+{
+ gUICtrlFactory->buildFloater(this,"floater_texture_ctrl.xml");
+
+ mTentativeLabel = LLUICtrlFactory::getTextBoxByName(this,"Multiple");
+
+ mResolutionLabel = LLUICtrlFactory::getTextBoxByName(this,"unknown");
+
+
+ childSetAction("Default",LLFloaterTexturePicker::onBtnSetToDefault,this);
+ childSetAction("None", LLFloaterTexturePicker::onBtnNone,this);
+ childSetAction("Blank", LLFloaterTexturePicker::onBtnWhite,this);
+
+
+ childSetCommitCallback("show_folders_check", onShowFolders, this);
+ childSetVisible("show_folders_check", FALSE);
+
+ mSearchEdit = (LLSearchEditor*)getCtrlByNameAndType("inventory search editor", WIDGET_TYPE_SEARCH_EDITOR);
+ mSearchEdit->setSearchCallback(onSearchEdit, this);
+
+ mInventoryPanel = (LLInventoryPanel*)this->getCtrlByNameAndType("inventory panel", WIDGET_TYPE_INVENTORY_PANEL);
+
+ if(mInventoryPanel)
+ {
+ U32 filter_types = 0x0;
+ filter_types |= 0x1 << LLInventoryType::IT_TEXTURE;
+ filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT;
+
+ mInventoryPanel->setAutoSelectOverride(true);
+ mInventoryPanel->setFilterTypes(filter_types);
+ mInventoryPanel->setFilterPermMask(getFilterPermMask());
+ mInventoryPanel->setSelectCallback(onSelectionChange, this);
+ mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
+ mInventoryPanel->setAllowMultiSelect(FALSE);
+ // Commented out to stop opening all folders with textures
+ // mInventoryPanel->openDefaultFolderForType(LLAssetType::AT_TEXTURE);
+
+ // don't put keyboard focus on selected item, because the selection callback
+ // will assume that this was user input
+ mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO);
+ }
+
+ mCanApplyImmediately = can_apply_immediately;
+ mNoCopyTextureSelected = FALSE;
+
+ childSetValue("apply_immediate_check", gSavedSettings.getBOOL("ApplyTextureImmediately"));
+ childSetCommitCallback("apply_immediate_check", onApplyImmediateCheck, this);
+
+ if (!can_apply_immediately)
+ {
+ childSetEnabled("show_folders_check", FALSE);
+ }
+
+ childSetAction("Pipette", LLFloaterTexturePicker::onBtnPipette,this);
+ childSetAction("Cancel", LLFloaterTexturePicker::onBtnCancel,this);
+ childSetAction("Select", LLFloaterTexturePicker::onBtnSelect,this);
+
+ // update permission filter once UI is fully initialized
+ updateFilterPermMask();
+
+ setCanMinimize(FALSE);
+}
+
+LLFloaterTexturePicker::~LLFloaterTexturePicker()
+{
+}
+
+void LLFloaterTexturePicker::setImageID(const LLUUID& image_id)
+{
+ if( mImageAssetID != image_id && mActive)
+ {
+ mNoCopyTextureSelected = FALSE;
+ mIsDirty = TRUE;
+ mImageAssetID = image_id;
+ LLUUID item_id = findItemID(mImageAssetID, FALSE);
+ if (item_id.isNull())
+ {
+ mInventoryPanel->clearSelection();
+ }
+ else
+ {
+ LLInventoryItem* itemp = gInventory.getItem(image_id);
+ if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID()))
+ {
+ // no copy texture
+ childSetValue("apply_immediate_check", FALSE);
+ mNoCopyTextureSelected = TRUE;
+ }
+ mInventoryPanel->setSelection(item_id, TAKE_FOCUS_NO);
+ }
+ }
+}
+
+void LLFloaterTexturePicker::setActive( BOOL active )
+{
+ if (!active && childGetValue("Pipette").asBoolean())
+ {
+ stopUsingPipette();
+ }
+ mActive = active;
+}
+
+void LLFloaterTexturePicker::setCanApplyImmediately(BOOL b)
+{
+ mCanApplyImmediately = b;
+ if (!mCanApplyImmediately)
+ {
+ childSetValue("apply_immediate_check", FALSE);
+ }
+ updateFilterPermMask();
+}
+
+void LLFloaterTexturePicker::stopUsingPipette()
+{
+ if (gToolMgr && gToolMgr->getCurrentTool(gKeyboard->currentMask(TRUE)) == gToolPipette)
+ {
+ gToolMgr->clearTransientTool();
+ }
+}
+
+void LLFloaterTexturePicker::updateImageStats()
+{
+ if (mTexturep.notNull())
+ {
+ //RN: have we received header data for this image?
+ if (mTexturep->getWidth(0) > 0 && mTexturep->getHeight(0) > 0)
+ {
+ std::ostringstream formatted_dims;
+ formatted_dims << llformat("Dimensions: %d x %d", mTexturep->getWidth(0),mTexturep->getHeight(0));
+ mResolutionLabel->setText(formatted_dims.str());
+ }
+ else
+ {
+ mResolutionLabel->setText("Dimensions: unknown");
+ }
+ if (gAgent.isGodlike())
+ {
+ LLString tstring = "Pick: " + mTexturep->getID().getString();
+ setTitle(tstring);
+ }
+ }
+}
+
+// virtual
+BOOL LLFloaterTexturePicker::handleDragAndDrop(
+ S32 x, S32 y, MASK mask,
+ BOOL drop,
+ EDragAndDropType cargo_type, void *cargo_data,
+ EAcceptance *accept,
+ LLString& tooltip_msg)
+{
+ BOOL handled = FALSE;
+
+ if (cargo_type == DAD_TEXTURE)
+ {
+ LLInventoryItem *item = (LLInventoryItem *)cargo_data;
+
+ BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
+ BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
+ BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
+ gAgent.getID());
+
+ PermissionMask item_perm_mask = 0;
+ if (copy) item_perm_mask |= PERM_COPY;
+ if (mod) item_perm_mask |= PERM_MODIFY;
+ if (xfer) item_perm_mask |= PERM_TRANSFER;
+
+ PermissionMask filter_perm_mask = getFilterPermMask();
+ if ( (item_perm_mask & filter_perm_mask) == filter_perm_mask )
+ {
+ if (drop)
+ {
+ setImageID( item->getAssetUUID() );
+ commitIfImmediateSet();
+ }
+
+ *accept = ACCEPT_YES_SINGLE;
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+
+ handled = TRUE;
+ lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFloaterTexturePicker " << getName() << llendl;
+
+ return handled;
+}
+
+// virtual
+void LLFloaterTexturePicker::onClose(bool app_quitting)
+{
+ if (mOwner)
+ {
+ mOwner->onFloaterClose();
+ }
+ stopUsingPipette();
+ destroy();
+}
+
+// virtual
+void LLFloaterTexturePicker::draw()
+{
+ if (mOwner)
+ {
+ // draw cone of context pointing back to texture swatch
+ LLRect owner_rect;
+ mOwner->localRectToOtherView(mOwner->getLocalRect(), &owner_rect, this);
+ LLRect local_rect = getLocalRect();
+ if (gFocusMgr.childHasKeyboardFocus(this) && mOwner->isInVisibleChain() && mContextConeOpacity > 0.001f)
+ {
+ LLGLSNoTexture no_texture;
+ LLGLEnable(GL_CULL_FACE);
+ glBegin(GL_QUADS);
+ {
+ glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+ glVertex2i(owner_rect.mLeft, owner_rect.mTop);
+ glVertex2i(owner_rect.mRight, owner_rect.mTop);
+ glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+ glVertex2i(local_rect.mRight, local_rect.mTop);
+ glVertex2i(local_rect.mLeft, local_rect.mTop);
+
+ glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+ glVertex2i(local_rect.mLeft, local_rect.mTop);
+ glVertex2i(local_rect.mLeft, local_rect.mBottom);
+ glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+ glVertex2i(owner_rect.mLeft, owner_rect.mBottom);
+ glVertex2i(owner_rect.mLeft, owner_rect.mTop);
+
+ glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+ glVertex2i(local_rect.mRight, local_rect.mBottom);
+ glVertex2i(local_rect.mRight, local_rect.mTop);
+ glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+ glVertex2i(owner_rect.mRight, owner_rect.mTop);
+ glVertex2i(owner_rect.mRight, owner_rect.mBottom);
+
+
+ glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+ glVertex2i(local_rect.mLeft, local_rect.mBottom);
+ glVertex2i(local_rect.mRight, local_rect.mBottom);
+ glColor4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+ glVertex2i(owner_rect.mRight, owner_rect.mBottom);
+ glVertex2i(owner_rect.mLeft, owner_rect.mBottom);
+ }
+ glEnd();
+ }
+ }
+
+ if (gFocusMgr.childHasMouseCapture(mDragHandle))
+ {
+ mContextConeOpacity = lerp(mContextConeOpacity, 1.f, LLCriticalDamp::getInterpolant(0.1f));
+ }
+ else
+ {
+ mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(0.2f));
+ }
+
+ updateImageStats();
+
+ // if we're inactive, gray out "apply immediate" checkbox
+ childSetEnabled("show_folders_check", mActive && mCanApplyImmediately && !mNoCopyTextureSelected);
+ childSetEnabled("Select", mActive);
+ childSetEnabled("Pipette", gToolMgr != NULL && mActive);
+ childSetValue("Pipette", gToolMgr && gToolMgr->getCurrentTool(gKeyboard->currentMask(TRUE)) == gToolPipette);
+
+ //RN: reset search bar to reflect actual search query (all caps, for example)
+ mSearchEdit->setText(mInventoryPanel->getFilterSubString());
+
+ //BOOL allow_copy = FALSE;
+ if( getVisible() && mOwner)
+ {
+ mTexturep = NULL;
+ if(mImageAssetID.notNull())
+ {
+ mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO);
+ mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW);
+ }
+
+ if (mTentativeLabel)
+ {
+ mTentativeLabel->setVisible( FALSE );
+ }
+
+ childSetEnabled("Default", mImageAssetID != mOwner->getDefaultImageAssetID());
+ childSetEnabled("Blank", mImageAssetID != mWhiteImageAssetID );
+ childSetEnabled("None", mOwner->getAllowNoTexture() && !mImageAssetID.isNull() );
+
+ LLFloater::draw();
+
+ if( isMinimized() )
+ {
+ return;
+ }
+
+ // Border
+ LLRect border( BORDER_PAD,
+ mRect.getHeight() - LLFLOATER_HEADER_SIZE - BORDER_PAD,
+ ((TEX_PICKER_MIN_WIDTH / 2) - TEXTURE_INVENTORY_PADDING - HPAD) - BORDER_PAD,
+ BORDER_PAD + FOOTER_HEIGHT + (mRect.getHeight() - TEX_PICKER_MIN_HEIGHT));
+ gl_rect_2d( border, LLColor4::black, FALSE );
+
+
+ // Interior
+ LLRect interior = border;
+ interior.stretch( -1 );
+
+ if( mTexturep )
+ {
+ if( mTexturep->getComponents() == 4 )
+ {
+ gl_rect_2d_checkerboard( interior );
+ }
+
+ gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep );
+
+ // Pump the priority
+ mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
+
+ // Draw Tentative Label over the image
+ if( mOwner->getTentative() && !mIsDirty )
+ {
+ mTentativeLabel->setVisible( TRUE );
+ drawChild(mTentativeLabel);
+ }
+ }
+ else
+ {
+ gl_rect_2d( interior, LLColor4::grey, TRUE );
+
+ // Draw X
+ gl_draw_x(interior, LLColor4::black );
+ }
+ }
+}
+
+// static
+/*
+void LLFloaterTexturePicker::onSaveAnotherCopyDialog( S32 option, void* userdata )
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+ if( 0 == option )
+ {
+ self->copyToInventoryFinal();
+ }
+}
+*/
+
+const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, BOOL copyable_only)
+{
+ LLViewerInventoryCategory::cat_array_t cats;
+ LLViewerInventoryItem::item_array_t items;
+ LLAssetIDMatches asset_id_matches(asset_id);
+ gInventory.collectDescendentsIf(LLUUID::null,
+ cats,
+ items,
+ LLInventoryModel::INCLUDE_TRASH,
+ asset_id_matches);
+
+ if (items.count())
+ {
+ // search for copyable version first
+ for (S32 i = 0; i < items.count(); i++)
+ {
+ LLInventoryItem* itemp = items[i];
+ LLPermissions item_permissions = itemp->getPermissions();
+ if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID()))
+ {
+ return itemp->getUUID();
+ }
+ }
+ // otherwise just return first instance, unless copyable requested
+ if (copyable_only)
+ {
+ return LLUUID::null;
+ }
+ else
+ {
+ return items[0]->getUUID();
+ }
+ }
+
+ return LLUUID::null;
+}
+
+PermissionMask LLFloaterTexturePicker::getFilterPermMask()
+{
+ bool apply_immediate = childGetValue("apply_immediate_check").asBoolean();
+ return apply_immediate ? mImmediateFilterPermMask : mNonImmediateFilterPermMask;
+}
+
+void LLFloaterTexturePicker::commitIfImmediateSet()
+{
+ bool apply_immediate = childGetValue("apply_immediate_check").asBoolean();
+ if (!mNoCopyTextureSelected && apply_immediate && mOwner)
+ {
+ mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CHANGE);
+ }
+}
+
+// static
+void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata)
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+ if (self->mOwner)
+ {
+ self->setImageID( self->mOwner->getDefaultImageAssetID() );
+ }
+ self->commitIfImmediateSet();
+}
+
+// static
+void LLFloaterTexturePicker::onBtnWhite(void* userdata)
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+ self->setImageID( self->mWhiteImageAssetID );
+ self->commitIfImmediateSet();
+}
+
+
+// static
+void LLFloaterTexturePicker::onBtnNone(void* userdata)
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+ self->setImageID( LLUUID::null );
+ self->commitIfImmediateSet();
+}
+
+/*
+// static
+void LLFloaterTexturePicker::onBtnRevert(void* userdata)
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+ self->setImageID( self->mOriginalImageAssetID );
+ // TODO: Change this to tell the owner to cancel. It needs to be
+ // smart enough to restore multi-texture selections.
+ self->mOwner->onFloaterCommit();
+ self->mIsDirty = FALSE;
+}*/
+
+// static
+void LLFloaterTexturePicker::onBtnCancel(void* userdata)
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+ self->setImageID( self->mOriginalImageAssetID );
+ if (self->mOwner)
+ {
+ self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CANCEL);
+ }
+ self->mIsDirty = FALSE;
+ self->close();
+}
+
+// static
+void LLFloaterTexturePicker::onBtnSelect(void* userdata)
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+ if (self->mOwner)
+ {
+ self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_SELECT);
+ }
+ self->close();
+}
+
+// static
+void LLFloaterTexturePicker::onBtnPipette( void* userdata )
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+
+ if ( self && gToolMgr)
+ {
+ BOOL pipette_active = self->childGetValue("Pipette").asBoolean();
+ pipette_active = !pipette_active;
+ if (pipette_active)
+ {
+ gToolPipette->setSelectCallback(onTextureSelect, self);
+ gToolMgr->setTransientTool(gToolPipette);
+ }
+ else
+ {
+ gToolMgr->clearTransientTool();
+ }
+ }
+
+}
+
+// static
+void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action, void* data)
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)data;
+ if (items.size())
+ {
+ LLFolderViewItem* first_item = items.front();
+ LLInventoryItem* itemp = gInventory.getItem(first_item->getListener()->getUUID());
+ self->mNoCopyTextureSelected = FALSE;
+ if (itemp)
+ {
+ if (!itemp->getPermissions().allowCopyBy(gAgent.getID()))
+ {
+ self->mNoCopyTextureSelected = TRUE;
+ }
+ self->mImageAssetID = itemp->getAssetUUID();
+ self->mIsDirty = TRUE;
+ if (user_action)
+ {
+ // only commit intentional selections, not implicit ones
+ self->commitIfImmediateSet();
+ }
+ }
+ }
+}
+
+// static
+void LLFloaterTexturePicker::onShowFolders(LLUICtrl* ctrl, void *user_data)
+{
+ LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
+ LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data;
+
+ if (check_box->get())
+ {
+ picker->mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
+ }
+ else
+ {
+ picker->mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NO_FOLDERS);
+ }
+}
+
+// static
+void LLFloaterTexturePicker::onApplyImmediateCheck(LLUICtrl* ctrl, void *user_data)
+{
+ LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data;
+
+ LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
+ gSavedSettings.setBOOL("ApplyTextureImmediately", check_box->get());
+
+ picker->updateFilterPermMask();
+ picker->commitIfImmediateSet();
+}
+
+void LLFloaterTexturePicker::updateFilterPermMask()
+{
+ mInventoryPanel->setFilterPermMask( getFilterPermMask() );
+}
+
+void LLFloaterTexturePicker::onSearchEdit(const LLString& search_string, void* user_data )
+{
+ LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data;
+
+ std::string filter_text = search_string;
+
+ if (filter_text.empty()&& picker->mInventoryPanel->getFilterSubString().empty())
+ {
+ // current filter and new filter empty, do nothing
+ return;
+ }
+ std::string upper_case_search_string = filter_text;
+ LLString::toUpper(upper_case_search_string);
+
+ picker->mInventoryPanel->setFilterSubString(upper_case_search_string);
+
+ LLFolderView* root_folder = picker->mInventoryPanel->getRootFolder();
+
+ //if (search_string.size())
+ //{
+ // LLSelectFirstFilteredItem filter;
+ // root_folder->applyFunctorRecursively(filter);
+ // //...and scroll to show it
+ // root_folder->scrollToShowSelection();
+ //}
+
+ KEY key = gKeyboard->currentKey();
+
+ if ((key == KEY_RETURN || key == KEY_DOWN) && gKeyboard->currentMask(FALSE) == MASK_NONE)
+ {
+ if (search_string.size())
+ {
+ LLSelectFirstFilteredItem filter;
+ root_folder->applyFunctorRecursively(filter);
+ //...and scroll to show it
+ root_folder->scrollToShowSelection();
+ }
+
+ if (!root_folder->getCurSelectedItem())
+ {
+ LLFolderViewItem* itemp = root_folder->getItemByID(gAgent.getInventoryRootID());
+ if (itemp)
+ {
+ root_folder->setSelection(itemp, FALSE, FALSE);
+ }
+ }
+
+ // move focus to inventory proper
+ root_folder->setFocus(TRUE);
+ root_folder->scrollToShowSelection();
+ }
+}
+
+//static
+void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te, void *data )
+{
+ LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)data;
+
+ LLUUID inventory_item_id = self->findItemID(te.getID(), TRUE);
+ if (self && inventory_item_id.notNull())
+ {
+ gToolPipette->setResult(TRUE, "");
+ self->setImageID(te.getID());
+
+ self->mNoCopyTextureSelected = FALSE;
+ LLInventoryItem* itemp = gInventory.getItem(inventory_item_id);
+
+ if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID()))
+ {
+ // no copy texture
+ self->mNoCopyTextureSelected = TRUE;
+ }
+
+ self->commitIfImmediateSet();
+ }
+ else
+ {
+ gToolPipette->setResult(FALSE, "You do not have a copy this \nof texture in your inventory");
+ }
+}
+
+///////////////////////////////////////////////////////////////////////
+// LLTextureCtrl
+
+LLTextureCtrl::LLTextureCtrl(
+ const std::string& name,
+ const LLRect &rect,
+ const std::string& label,
+ const LLUUID &image_id,
+ const LLUUID &default_image_id,
+ const std::string& default_image_name )
+ :
+ LLUICtrl(name, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP),
+ mDragCallback(NULL),
+ mDropCallback(NULL),
+ mOnCancelCallback(NULL),
+ mOnSelectCallback(NULL),
+ mBorderColor( gColors.getColor("DefaultHighlightLight") ),
+ mImageAssetID( image_id ),
+ mDefaultImageAssetID( default_image_id ),
+ mDefaultImageName( default_image_name ),
+ mLabel( label ),
+ mAllowNoTexture( FALSE ),
+ mImmediateFilterPermMask( PERM_NONE ),
+ mNonImmediateFilterPermMask( PERM_NONE ),
+ mCanApplyImmediately( FALSE ),
+ mNeedsRawImageData( FALSE ),
+ mValid( TRUE )
+{
+ mCaption = new LLTextBox( label,
+ LLRect( 0, BTN_HEIGHT_SMALL, mRect.getWidth(), 0 ),
+ NULL,
+ LLFontGL::sSansSerifSmall );
+ mCaption->setFollows( FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM );
+ addChild( mCaption );
+
+ S32 image_top = mRect.getHeight();
+ S32 image_bottom = BTN_HEIGHT_SMALL;
+ S32 image_middle = (image_top + image_bottom) / 2;
+ S32 line_height = llround(LLFontGL::sSansSerifSmall->getLineHeight());
+
+ mTentativeLabel = new LLTextBox( "Multiple",
+ LLRect(
+ 0, image_middle + line_height / 2,
+ mRect.getWidth(), image_middle - line_height / 2 ),
+ NULL,
+ LLFontGL::sSansSerifSmall );
+ mTentativeLabel->setHAlign( LLFontGL::HCENTER );
+ mTentativeLabel->setFollowsAll();
+ addChild( mTentativeLabel );
+
+ LLRect border_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
+ border_rect.mBottom += BTN_HEIGHT_SMALL;
+ mBorder = new LLViewBorder("border", border_rect, LLViewBorder::BEVEL_IN);
+ addChild(mBorder);
+
+ setEnabled(TRUE); // for the tooltip
+}
+
+
+LLTextureCtrl::~LLTextureCtrl()
+{
+ closeFloater();
+}
+
+// virtual
+LLXMLNodePtr LLTextureCtrl::getXML(bool save_children) const
+{
+ LLXMLNodePtr node = LLUICtrl::getXML();
+
+ node->createChild("label", TRUE)->setStringValue(getLabel());
+
+ node->createChild("default_image_name", TRUE)->setStringValue(getDefaultImageName());
+
+ node->createChild("allow_no_texture", TRUE)->setBoolValue(mAllowNoTexture);
+
+ node->createChild("can_apply_immediately", TRUE)->setBoolValue(mCanApplyImmediately );
+
+ return node;
+}
+
+LLView* LLTextureCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+{
+ LLString name("texture_picker");
+ node->getAttributeString("name", name);
+
+ LLRect rect;
+ createRect(node, rect, parent);
+
+ LLString label;
+ node->getAttributeString("label", label);
+
+ LLString image_id("");
+ node->getAttributeString("image", image_id);
+
+ LLString default_image_id("");
+ node->getAttributeString("default_image", default_image_id);
+
+ LLString default_image_name("Default");
+ node->getAttributeString("default_image_name", default_image_name);
+
+ BOOL allow_no_texture = FALSE;
+ node->getAttributeBOOL("allow_no_texture", allow_no_texture);
+
+ BOOL can_apply_immediately = FALSE;
+ node->getAttributeBOOL("can_apply_immediately", can_apply_immediately);
+
+ if (label.empty())
+ {
+ label.assign(node->getValue());
+ }
+
+ LLTextureCtrl* texture_picker = new LLTextureCtrl(
+ name,
+ rect,
+ label,
+ LLUUID(image_id),
+ LLUUID(default_image_id),
+ default_image_name );
+ texture_picker->setAllowNoTexture(allow_no_texture);
+ texture_picker->setCanApplyImmediately(can_apply_immediately);
+
+ texture_picker->initFromXML(node, parent);
+
+ return texture_picker;
+}
+
+void LLTextureCtrl::setCaption(const LLString& caption)
+{
+ mCaption->setText( caption );
+}
+
+void LLTextureCtrl::setCanApplyImmediately(BOOL b)
+{
+ mCanApplyImmediately = b;
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle);
+ if( floaterp )
+ {
+ floaterp->setCanApplyImmediately(b);
+ }
+}
+
+void LLTextureCtrl::setVisible( BOOL visible )
+{
+ if( !visible )
+ {
+ closeFloater();
+ }
+ LLUICtrl::setVisible( visible );
+}
+
+void LLTextureCtrl::setEnabled( BOOL enabled )
+{
+ if( enabled )
+ {
+ setToolTip( "Click to choose a picture" );
+ }
+ else
+ {
+ setToolTip( "" );
+ //FIXME: would be better to keep floater open
+ // and show disabled state
+ closeFloater();
+ }
+
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle);
+ if( floaterp )
+ {
+ floaterp->setActive(enabled);
+ }
+
+ mCaption->setEnabled( enabled );
+
+ LLUICtrl::setEnabled( enabled );
+}
+
+void LLTextureCtrl::setValid(BOOL valid )
+{
+ mValid = valid;
+ if (!valid)
+ {
+ LLFloaterTexturePicker* pickerp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle);
+ if (pickerp)
+ {
+ pickerp->setActive(FALSE);
+ }
+ }
+}
+
+
+// virtual
+void LLTextureCtrl::clear()
+{
+ setImageAssetID(LLUUID::null);
+}
+
+void LLTextureCtrl::setLabel(const LLString& label)
+{
+ mLabel = label;
+ mCaption->setText(label);
+}
+
+void LLTextureCtrl::showPicker(BOOL take_focus)
+{
+ LLFloater* floaterp = LLFloater::getFloaterByHandle(mFloaterHandle);
+
+ // Show the dialog
+ if( floaterp )
+ {
+ floaterp->open( );
+ }
+ else
+ {
+ if( !mLastFloaterLeftTop.mX && !mLastFloaterLeftTop.mY )
+ {
+ gFloaterView->getNewFloaterPosition(&mLastFloaterLeftTop.mX, &mLastFloaterLeftTop.mY);
+ }
+ LLRect rect = gSavedSettings.getRect("TexturePickerRect");
+ rect.translate( mLastFloaterLeftTop.mX - rect.mLeft, mLastFloaterLeftTop.mY - rect.mTop );
+
+ floaterp = new LLFloaterTexturePicker(
+ this,
+ rect,
+ mLabel,
+ mImmediateFilterPermMask,
+ mNonImmediateFilterPermMask,
+ mCanApplyImmediately);
+ mFloaterHandle = floaterp->getHandle();
+
+ gFloaterView->getParentFloater(this)->addDependentFloater(floaterp);
+ floaterp->open();
+ }
+
+ if (take_focus)
+ {
+ floaterp->setFocus(TRUE);
+ }
+}
+
+
+void LLTextureCtrl::closeFloater()
+{
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle);
+ if( floaterp )
+ {
+ floaterp->setOwner(NULL);
+ floaterp->close();
+ }
+}
+
+// Allow us to download textures quickly when floater is shown
+class LLTextureFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
+{
+public:
+ virtual void done()
+ {
+ // We need to find textures in all folders, so get the main
+ // background download going.
+ gInventory.startBackgroundFetch();
+ gInventory.removeObserver(this);
+ delete this;
+ }
+};
+
+BOOL LLTextureCtrl::handleHover(S32 x, S32 y, MASK mask)
+{
+ getWindow()->setCursor(UI_CURSOR_HAND);
+ return TRUE;
+}
+
+
+BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ BOOL handled = LLUICtrl::handleMouseDown( x, y , mask );
+ if( handled )
+ {
+ showPicker(FALSE);
+
+ //grab textures first...
+ gInventory.startBackgroundFetch(gInventory.findCategoryUUIDForType(LLAssetType::AT_TEXTURE));
+ //...then start full inventory fetch.
+ gInventory.startBackgroundFetch();
+ }
+ return handled;
+}
+
+void LLTextureCtrl::onFloaterClose()
+{
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle);
+
+ if (floaterp)
+ {
+ floaterp->setOwner(NULL);
+ mLastFloaterLeftTop.set( floaterp->getRect().mLeft, floaterp->getRect().mTop );
+ }
+
+ mFloaterHandle.markDead();
+}
+
+void LLTextureCtrl::onFloaterCommit(ETexturePickOp op)
+{
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle);
+
+ if( floaterp && mEnabled)
+ {
+ if( floaterp->isDirty() )
+ {
+ setTentative( FALSE );
+ mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE);
+ lldebugs << "mImageItemID: " << mImageItemID << llendl;
+ mImageAssetID = floaterp->getAssetID();
+ lldebugs << "mImageAssetID: " << mImageAssetID << llendl;
+ if (op == TEXTURE_SELECT && mOnSelectCallback)
+ {
+ mOnSelectCallback(this, mCallbackUserData);
+ }
+ else if (op == TEXTURE_CANCEL && mOnCancelCallback)
+ {
+ mOnCancelCallback(this, mCallbackUserData);
+ }
+ else
+ {
+ onCommit();
+ }
+ }
+ }
+}
+
+void LLTextureCtrl::setImageAssetID( const LLUUID& asset_id )
+{
+ if( mImageAssetID != asset_id )
+ {
+ mImageItemID.setNull();
+ mImageAssetID = asset_id;
+ LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)LLFloater::getFloaterByHandle(mFloaterHandle);
+ if( floaterp && getEnabled() )
+ {
+ floaterp->setImageID( asset_id );
+ floaterp->setDirty( FALSE );
+ }
+ }
+}
+
+BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask,
+ BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
+ EAcceptance *accept,
+ LLString& tooltip_msg)
+{
+ BOOL handled = FALSE;
+
+ // this downcast may be invalid - but if the second test below
+ // returns true, then the cast was valid, and we can perform
+ // the third test without problems.
+ LLInventoryItem* item = (LLInventoryItem*)cargo_data;
+ if (mEnabled && (cargo_type == DAD_TEXTURE) && allowDrop(item))
+ {
+ if (drop)
+ {
+ if(doDrop(item))
+ {
+ // This removes the 'Multiple' overlay, since
+ // there is now only one texture selected.
+ setTentative( FALSE );
+ onCommit();
+ }
+ }
+
+ *accept = ACCEPT_YES_SINGLE;
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
+
+ handled = TRUE;
+ lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLTextureCtrl " << getName() << llendl;
+
+ return handled;
+}
+
+void LLTextureCtrl::draw()
+{
+ if( getVisible() )
+ {
+ mBorder->setKeyboardFocusHighlight(hasFocus());
+
+ if (mImageAssetID.isNull() || !mValid)
+ {
+ mTexturep = NULL;
+ }
+ else
+ {
+ mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO);
+ mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW);
+ }
+
+ // Border
+ LLRect border( 0, mRect.getHeight(), mRect.getWidth(), BTN_HEIGHT_SMALL );
+ gl_rect_2d( border, mBorderColor, FALSE );
+
+ // Interior
+ LLRect interior = border;
+ interior.stretch( -1 );
+
+ if( mTexturep )
+ {
+ if( mTexturep->getComponents() == 4 )
+ {
+ gl_rect_2d_checkerboard( interior );
+ }
+
+ gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep);
+ mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) );
+ }
+ else
+ {
+ gl_rect_2d( interior, LLColor4::grey, TRUE );
+
+ // Draw X
+ gl_draw_x( interior, LLColor4::black );
+ }
+
+ mTentativeLabel->setVisible( !mTexturep.isNull() && mTentative );
+
+ LLUICtrl::draw();
+ }
+}
+
+BOOL LLTextureCtrl::allowDrop(LLInventoryItem* item)
+{
+ BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
+ BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
+ BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
+ gAgent.getID());
+
+ PermissionMask item_perm_mask = 0;
+ if (copy) item_perm_mask |= PERM_COPY;
+ if (mod) item_perm_mask |= PERM_MODIFY;
+ if (xfer) item_perm_mask |= PERM_TRANSFER;
+
+ PermissionMask filter_perm_mask = mCanApplyImmediately ?
+ mImmediateFilterPermMask : mNonImmediateFilterPermMask;
+ if ( (item_perm_mask & filter_perm_mask) == filter_perm_mask )
+ {
+ if(mDragCallback)
+ {
+ return mDragCallback(this, item, mCallbackUserData);
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+BOOL LLTextureCtrl::doDrop(LLInventoryItem* item)
+{
+ // call the callback if it exists.
+ if(mDropCallback)
+ {
+ // if it returns TRUE, we return TRUE, and therefore the
+ // commit is called above.
+ return mDropCallback(this, item, mCallbackUserData);
+ }
+
+ // no callback installed, so just set the image ids and carry on.
+ setImageAssetID( item->getAssetUUID() );
+ mImageItemID = item->getUUID();
+ return TRUE;
+}
+
+BOOL LLTextureCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent)
+{
+ if( getVisible() && mEnabled && !called_from_parent && ' ' == uni_char )
+ {
+ showPicker(TRUE);
+ return TRUE;
+ }
+ return LLUICtrl::handleUnicodeCharHere(uni_char, called_from_parent);
+}
+
+void LLTextureCtrl::setValue( LLSD value )
+{
+ setImageAssetID(value.asUUID());
+}
+
+LLSD LLTextureCtrl::getValue() const
+{
+ return LLSD(getImageAssetID());
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// LLToolTexEyedropper
+
+class LLToolTexEyedropper : public LLTool
+{
+public:
+ LLToolTexEyedropper( void (*callback)(const LLUUID& obj_id, const LLUUID& image_id, void* userdata ), void* userdata );
+ virtual ~LLToolTexEyedropper();
+ virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ virtual BOOL handleHover(S32 x, S32 y, MASK mask);
+
+protected:
+ void (*mCallback)(const LLUUID& obj_id, const LLUUID& image_id, void* userdata );
+ void* mCallbackUserData;
+};
+
+
+LLToolTexEyedropper::LLToolTexEyedropper(
+ void (*callback)(const LLUUID& obj_id, const LLUUID& image_id, void* userdata ),
+ void* userdata )
+ : LLTool("texeyedropper"),
+ mCallback( callback ),
+ mCallbackUserData( userdata )
+{
+}
+
+LLToolTexEyedropper::~LLToolTexEyedropper()
+{
+}
+
+
+BOOL LLToolTexEyedropper::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ LLViewerObject* hit_obj = gViewerWindow->lastObjectHit();
+ if (hit_obj &&
+ !hit_obj->isAvatar())
+ {
+ if( (0 <= gLastHitObjectFace) && (gLastHitObjectFace < hit_obj->getNumTEs()) )
+ {
+ LLViewerImage* image = hit_obj->getTEImage( gLastHitObjectFace );
+ if( image )
+ {
+ if( mCallback )
+ {
+ mCallback( hit_obj->getID(), image->getID(), mCallbackUserData );
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLToolTexEyedropper::handleHover(S32 x, S32 y, MASK mask)
+{
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolTexEyedropper" << llendl;
+ gViewerWindow->getWindow()->setCursor(UI_CURSOR_CROSS); // TODO: better cursor
+ return TRUE;
+}
+