diff options
Diffstat (limited to 'indra/newview/llpanelclassified.cpp')
-rw-r--r-- | indra/newview/llpanelclassified.cpp | 411 |
1 files changed, 358 insertions, 53 deletions
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 6f0b7df935..021e1f5159 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -114,6 +114,23 @@ public: }; static LLDispatchClassifiedClickThrough sClassifiedClickThrough; +// Just to debug errors. Can be thrown away later. +class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder +{ + LOG_CLASS(LLClassifiedClickMessageResponder); + +public: + // If we get back an error (not found, etc...), handle it here + virtual void errorWithContent( + U32 status, + const std::string& reason, + const LLSD& content) + { + llwarns << "Sending click message failed (" << status << "): [" << reason << "]" << llendl; + llwarns << "Content: [" << content << "]" << llendl; + } +}; + /* Re-expose this if we need to have classified ad HTML detail pages. JC @@ -1166,6 +1183,7 @@ LLPanelClassifiedInfo::LLPanelClassifiedInfo() , mTeleportClicksNew(0) , mMapClicksNew(0) , mProfileClicksNew(0) + , mSnapshotCtrl(NULL) { sAllPanels.push_back(this); } @@ -1195,7 +1213,8 @@ BOOL LLPanelClassifiedInfo::postBuild() mScrollingPanelMinHeight = mScrollContainer->getScrolledViewRect().getHeight(); mScrollingPanelWidth = mScrollingPanel->getRect().getWidth(); - mSnapshotRect = getChild<LLUICtrl>("classified_snapshot")->getRect(); + mSnapshotCtrl = getChild<LLTextureCtrl>("classified_snapshot"); + mSnapshotRect = getDefaultSnapshotRect(); return TRUE; } @@ -1229,12 +1248,13 @@ void LLPanelClassifiedInfo::reshape(S32 width, S32 height, BOOL called_from_pare mScrollingPanel->reshape(mScrollingPanelWidth + scrollbar_size, scroll_height); } - mSnapshotRect = getChild<LLUICtrl>("classified_snapshot")->getRect(); + mSnapshotRect = getDefaultSnapshotRect(); + stretchSnapshot(); } void LLPanelClassifiedInfo::onOpen(const LLSD& key) { - LLUUID avatar_id = key["avatar_id"]; + LLUUID avatar_id = key["classified_creator_id"]; if(avatar_id.isNull()) { return; @@ -1249,11 +1269,15 @@ void LLPanelClassifiedInfo::onOpen(const LLSD& key) resetData(); resetControls(); + scrollToTop(); setClassifiedId(key["classified_id"]); - setClassifiedName(key["name"]); - setDescription(key["desc"]); - setSnapshotId(key["snapshot_id"]); + setClassifiedName(key["classified_name"]); + setDescription(key["classified_desc"]); + setSnapshotId(key["classified_snapshot_id"]); + setFromSearch(key["from_search"]); + + llinfos << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << llendl; LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); @@ -1270,6 +1294,10 @@ void LLPanelClassifiedInfo::onOpen(const LLSD& key) LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(getClassifiedId())); } + // Update classified click stats. + // *TODO: Should we do this when opening not from search? + sendClickMessage("profile"); + setInfoLoaded(false); } @@ -1285,6 +1313,8 @@ void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType t setSnapshotId(c_info->snapshot_id); setParcelId(c_info->parcel_id); setPosGlobal(c_info->pos_global); + setSimName(c_info->sim_name); + setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); childSetValue("category", LLClassifiedInfo::sCategories[c_info->category]); @@ -1295,7 +1325,12 @@ void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType t bool mature = is_cf_mature(c_info->flags); childSetValue("content_type", mature ? mature_str : pg_str); - childSetValue("auto_renew", is_cf_auto_renew(c_info->flags)); + getChild<LLIconCtrl>("content_type_moderate")->setVisible(mature); + getChild<LLIconCtrl>("content_type_general")->setVisible(!mature); + + std::string auto_renew_str = is_cf_auto_renew(c_info->flags) ? + getString("auto_renew_on") : getString("auto_renew_off"); + childSetValue("auto_renew", auto_renew_str); price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing)); childSetValue("price_for_listing", LLSD(price_str)); @@ -1316,10 +1351,28 @@ void LLPanelClassifiedInfo::resetData() setClassifiedLocation(LLStringUtil::null); setClassifiedId(LLUUID::null); setSnapshotId(LLUUID::null); - mPosGlobal.clearVec(); - childSetValue("category", LLStringUtil::null); - childSetValue("content_type", LLStringUtil::null); + setPosGlobal(LLVector3d::zero); + setParcelId(LLUUID::null); + setSimName(LLStringUtil::null); + setFromSearch(false); + + // reset click stats + mTeleportClicksOld = 0; + mMapClicksOld = 0; + mProfileClicksOld = 0; + mTeleportClicksNew = 0; + mMapClicksNew = 0; + mProfileClicksNew = 0; + + childSetText("category", LLStringUtil::null); + childSetText("content_type", LLStringUtil::null); childSetText("click_through_text", LLStringUtil::null); + childSetText("price_for_listing", LLStringUtil::null); + childSetText("auto_renew", LLStringUtil::null); + childSetText("creation_date", LLStringUtil::null); + childSetText("click_through_text", LLStringUtil::null); + getChild<LLIconCtrl>("content_type_moderate")->setVisible(FALSE); + getChild<LLIconCtrl>("content_type_general")->setVisible(FALSE); } void LLPanelClassifiedInfo::resetControls() @@ -1357,14 +1410,14 @@ void LLPanelClassifiedInfo::setClassifiedLocation(const std::string& location) childSetValue("classified_location", location); } +std::string LLPanelClassifiedInfo::getClassifiedLocation() +{ + return childGetValue("classified_location").asString(); +} + void LLPanelClassifiedInfo::setSnapshotId(const LLUUID& id) { - childSetValue("classified_snapshot", id); - if(!mSnapshotStreched) - { - LLUICtrl* snapshot = getChild<LLUICtrl>("classified_snapshot"); - snapshot->setRect(mSnapshotRect); - } + mSnapshotCtrl->setValue(id); mSnapshotStreched = false; } @@ -1374,7 +1427,10 @@ void LLPanelClassifiedInfo::draw() // Stretch in draw because it takes some time to load a texture, // going to try to stretch snapshot until texture is loaded - stretchSnapshot(); + if(!mSnapshotStreched) + { + stretchSnapshot(); + } } LLUUID LLPanelClassifiedInfo::getSnapshotId() @@ -1435,6 +1491,13 @@ void LLPanelClassifiedInfo::setClickThrough( ct_str.setArg("[PROFILE]", llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)); self->childSetText("click_through_text", ct_str.getString()); + // *HACK: remove this when there is enough room for click stats in the info panel + self->childSetToolTip("click_through_text", ct_str.getString()); + + llinfos << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld) + << ", map: " << llformat("%d", self->mMapClicksNew + self->mMapClicksOld) + << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld) + << llendl; } } @@ -1474,10 +1537,9 @@ void LLPanelClassifiedInfo::stretchSnapshot() // *NOTE dzaporozhan // Could be moved to LLTextureCtrl - LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("classified_snapshot"); - LLViewerFetchedTexture* texture = texture_ctrl->getTexture(); + LLViewerFetchedTexture* texture = mSnapshotCtrl->getTexture(); - if(!texture || mSnapshotStreched) + if(!texture) { return; } @@ -1485,11 +1547,16 @@ void LLPanelClassifiedInfo::stretchSnapshot() if(0 == texture->getOriginalWidth() || 0 == texture->getOriginalHeight()) { // looks like texture is not loaded yet - llinfos << "Missing image size" << llendl; return; } LLRect rc = mSnapshotRect; + // *HACK dzaporozhan + // LLTextureCtrl uses BTN_HEIGHT_SMALL as bottom for texture which causes + // drawn texture to be smaller than expected. (see LLTextureCtrl::draw()) + // Lets increase texture height to force texture look as expected. + rc.mBottom -= BTN_HEIGHT_SMALL; + F32 t_width = texture->getFullWidth(); F32 t_height = texture->getFullHeight(); @@ -1499,13 +1566,66 @@ void LLPanelClassifiedInfo::stretchSnapshot() t_height *= ratio; rc.setCenterAndSize(rc.getCenterX(), rc.getCenterY(), llfloor(t_width), llfloor(t_height)); - texture_ctrl->setRect(rc); + mSnapshotCtrl->setShape(rc); mSnapshotStreched = true; } +LLRect LLPanelClassifiedInfo::getDefaultSnapshotRect() +{ + // Using scroll container makes getting default rect a hard task + // because rect in postBuild() and in first reshape() is not the same. + // Using snapshot_panel makes it easier to reshape snapshot. + return getChild<LLUICtrl>("snapshot_panel")->getLocalRect(); +} + +void LLPanelClassifiedInfo::scrollToTop() +{ + LLScrollContainer* scrollContainer = findChild<LLScrollContainer>("profile_scroll"); + if (scrollContainer) + scrollContainer->goToTop(); +} + +// static +// *TODO: move out of the panel +void LLPanelClassifiedInfo::sendClickMessage( + const std::string& type, + bool from_search, + const LLUUID& classified_id, + const LLUUID& parcel_id, + const LLVector3d& global_pos, + const std::string& sim_name) +{ + // You're allowed to click on your own ads to reassure yourself + // that the system is working. + LLSD body; + body["type"] = type; + body["from_search"] = from_search; + body["classified_id"] = classified_id; + body["parcel_id"] = parcel_id; + body["dest_pos_global"] = global_pos.getValue(); + body["region_name"] = sim_name; + + std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); + llinfos << "Sending click msg via capability (url=" << url << ")" << llendl; + llinfos << "body: [" << body << "]" << llendl; + LLHTTPClient::post(url, body, new LLClassifiedClickMessageResponder()); +} + +void LLPanelClassifiedInfo::sendClickMessage(const std::string& type) +{ + sendClickMessage( + type, + fromSearch(), + getClassifiedId(), + getParcelId(), + getPosGlobal(), + getSimName()); +} + void LLPanelClassifiedInfo::onMapClick() { + sendClickMessage("map"); LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); LLFloaterReg::showInstance("world_map", "center"); } @@ -1514,6 +1634,7 @@ void LLPanelClassifiedInfo::onTeleportClick() { if (!getPosGlobal().isExactlyZero()) { + sendClickMessage("teleport"); gAgent.teleportViaLocation(getPosGlobal()); LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); } @@ -1535,7 +1656,9 @@ static const S32 CB_ITEM_PG = 1; LLPanelClassifiedEdit::LLPanelClassifiedEdit() : LLPanelClassifiedInfo() , mIsNew(false) + , mIsNewWithErrors(false) , mCanClose(false) + , mPublishFloater(NULL) { } @@ -1587,22 +1710,17 @@ BOOL LLPanelClassifiedEdit::postBuild() childSetAction("save_changes_btn", boost::bind(&LLPanelClassifiedEdit::onSaveClick, this)); childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelClassifiedEdit::onSetLocationClick, this)); + mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelClassifiedEdit::onTextureSelected, this)); + return TRUE; } -void LLPanelClassifiedEdit::onOpen(const LLSD& key) +void LLPanelClassifiedEdit::fillIn(const LLSD& key) { - LLUUID classified_id = key["classified_id"]; - - mIsNew = classified_id.isNull(); + setAvatarId(gAgent.getID()); - if(mIsNew) + if(key.isUndefined()) { - setAvatarId(gAgent.getID()); - - resetData(); - resetControls(); - setPosGlobal(gAgent.getPositionGlobal()); LLUUID snapshot_id = LLUUID::null; @@ -1625,22 +1743,55 @@ void LLPanelClassifiedEdit::onOpen(const LLSD& key) childSetValue("classified_name", makeClassifiedName()); childSetValue("classified_desc", desc); setSnapshotId(snapshot_id); - setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); - // server will set valid parcel id setParcelId(LLUUID::null); + } + else + { + setClassifiedId(key["classified_id"]); + setClassifiedName(key["name"]); + setDescription(key["desc"]); + setSnapshotId(key["snapshot_id"]); + setCategory((U32)key["category"].asInteger()); + setContentType((U32)key["content_type"].asInteger()); + setClassifiedLocation(key["location_text"]); + childSetValue("auto_renew", key["auto_renew"]); + childSetValue("price_for_listing", key["price_for_listing"].asInteger()); + } +} - enableVerbs(true); - enableEditing(true); +void LLPanelClassifiedEdit::onOpen(const LLSD& key) +{ + mIsNew = key.isUndefined(); + + scrollToTop(); + + // classified is not created yet + bool is_new = isNew() || isNewWithErrors(); + + if(is_new) + { + resetData(); + resetControls(); + + fillIn(key); + + if(isNew()) + { + LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); + } } else { LLPanelClassifiedInfo::onOpen(key); - enableVerbs(false); - enableEditing(false); } + std::string save_btn_label = is_new ? getString("publish_label") : getString("save_label"); + childSetLabelArg("save_changes_btn", "[LABEL]", save_btn_label); + + enableVerbs(is_new); + enableEditing(is_new); resetDirty(); setInfoLoaded(false); } @@ -1652,6 +1803,14 @@ void LLPanelClassifiedEdit::processProperties(void* data, EAvatarProcessorType t LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data); if(c_info && getClassifiedId() == c_info->classified_id) { + // see LLPanelClassifiedEdit::sendUpdate() for notes + mIsNewWithErrors = false; + // for just created classified - panel will probably be closed when we get here. + if(!getVisible()) + { + return; + } + enableEditing(true); setClassifiedName(c_info->name); @@ -1660,18 +1819,23 @@ void LLPanelClassifiedEdit::processProperties(void* data, EAvatarProcessorType t setPosGlobal(c_info->pos_global); setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); - getChild<LLComboBox>("category")->setCurrentByIndex(c_info->category + 1); - getChild<LLComboBox>("category")->resetDirty(); + // *HACK see LLPanelClassifiedEdit::sendUpdate() + setCategory(c_info->category - 1); bool mature = is_cf_mature(c_info->flags); bool auto_renew = is_cf_auto_renew(c_info->flags); - getChild<LLComboBox>("content_type")->setCurrentByIndex(mature ? CB_ITEM_MATURE : CB_ITEM_PG); + setContentType(mature ? CB_ITEM_MATURE : CB_ITEM_PG); childSetValue("auto_renew", auto_renew); childSetValue("price_for_listing", c_info->price_for_listing); + childSetEnabled("price_for_listing", isNew()); resetDirty(); setInfoLoaded(true); + enableVerbs(false); + + // for just created classified - in case user opened edit panel before processProperties() callback + childSetLabelArg("save_changes_btn", "[LABEL]", getString("save_label")); } } } @@ -1702,19 +1866,24 @@ void LLPanelClassifiedEdit::resetDirty() LLPanelClassifiedInfo::resetDirty(); getChild<LLUICtrl>("classified_snapshot")->resetDirty(); getChild<LLUICtrl>("classified_name")->resetDirty(); - getChild<LLUICtrl>("classified_desc")->resetDirty(); + + LLTextEditor* desc = getChild<LLTextEditor>("classified_desc"); + // call blockUndo() to really reset dirty(and make isDirty work as intended) + desc->blockUndo(); + desc->resetDirty(); + getChild<LLUICtrl>("category")->resetDirty(); getChild<LLUICtrl>("content_type")->resetDirty(); getChild<LLUICtrl>("auto_renew")->resetDirty(); getChild<LLUICtrl>("price_for_listing")->resetDirty(); } -void LLPanelClassifiedEdit::setSaveCallback(const commit_callback_t& cb) +void LLPanelClassifiedEdit::setSaveCallback(const commit_signal_t::slot_type& cb) { - getChild<LLButton>("save_changes_btn")->setClickedCallback(cb); + mSaveButtonClickedSignal.connect(cb); } -void LLPanelClassifiedEdit::setCancelCallback(const commit_callback_t& cb) +void LLPanelClassifiedEdit::setCancelCallback(const commit_signal_t::slot_type& cb) { getChild<LLButton>("cancel_btn")->setClickedCallback(cb); } @@ -1724,9 +1893,10 @@ void LLPanelClassifiedEdit::resetControls() LLPanelClassifiedInfo::resetControls(); getChild<LLComboBox>("category")->setCurrentByIndex(0); - getChild<LLComboBox>("content_type")->setCurrentByIndex(0); + getChild<LLIconsComboBox>("content_type")->setCurrentByIndex(0); childSetValue("auto_renew", false); childSetValue("price_for_listing", MINIMUM_PRICE_FOR_LISTING); + childSetEnabled("price_for_listing", TRUE); } bool LLPanelClassifiedEdit::canClose() @@ -1734,20 +1904,54 @@ bool LLPanelClassifiedEdit::canClose() return mCanClose; } +void LLPanelClassifiedEdit::draw() +{ + LLPanel::draw(); + + // Need to re-stretch on every draw because LLTextureCtrl::onSelectCallback + // does not trigger callbacks when user navigates through images. + stretchSnapshot(); +} + +void LLPanelClassifiedEdit::stretchSnapshot() +{ + LLPanelClassifiedInfo::stretchSnapshot(); + + getChild<LLUICtrl>("edit_icon")->setShape(mSnapshotCtrl->getRect()); +} + +U32 LLPanelClassifiedEdit::getContentType() +{ + LLComboBox* ct_cb = getChild<LLComboBox>("content_type"); + return ct_cb->getCurrentIndex(); +} + +void LLPanelClassifiedEdit::setContentType(U32 content_type) +{ + LLIconsComboBox* ct_cb = getChild<LLIconsComboBox>("content_type"); + ct_cb->setCurrentByIndex(content_type); + ct_cb->resetDirty(); +} + +bool LLPanelClassifiedEdit::getAutoRenew() +{ + return childGetValue("auto_renew").asBoolean(); +} + void LLPanelClassifiedEdit::sendUpdate() { LLAvatarClassifiedInfo c_data; if(getClassifiedId().isNull()) { - LLUUID id; - id.generate(); - setClassifiedId(id); + setClassifiedId(LLUUID::generateNewID()); } c_data.agent_id = gAgent.getID(); c_data.classified_id = getClassifiedId(); - c_data.category = getCategory(); + // *HACK + // Categories on server start with 1 while combo-box index starts with 0 + c_data.category = getCategory() + 1; c_data.name = getClassifiedName(); c_data.description = getDescription(); c_data.parcel_id = getParcelId(); @@ -1757,19 +1961,34 @@ void LLPanelClassifiedEdit::sendUpdate() c_data.price_for_listing = getPriceForListing(); LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data); + + if(isNew()) + { + // Lets assume there will be some error. + // Successful sendClassifiedInfoUpdate will trigger processProperties and + // let us know there was no error. + mIsNewWithErrors = true; + } } U32 LLPanelClassifiedEdit::getCategory() { LLComboBox* cat_cb = getChild<LLComboBox>("category"); - return cat_cb->getCurrentIndex() + 1; + return cat_cb->getCurrentIndex(); +} + +void LLPanelClassifiedEdit::setCategory(U32 category) +{ + LLComboBox* cat_cb = getChild<LLComboBox>("category"); + cat_cb->setCurrentByIndex(category); + cat_cb->resetDirty(); } U8 LLPanelClassifiedEdit::getFlags() { bool auto_renew = childGetValue("auto_renew").asBoolean(); - LLComboBox* content_cb = getChild<LLComboBox>("content_type"); + LLComboBox* content_cb = getChild<LLIconsComboBox>("content_type"); bool mature = content_cb->getCurrentIndex() == CB_ITEM_MATURE; return pack_classified_flags_request(auto_renew, false, mature, false); @@ -1821,6 +2040,11 @@ S32 LLPanelClassifiedEdit::getPriceForListing() return childGetValue("price_for_listing").asInteger(); } +void LLPanelClassifiedEdit::setPriceForListing(S32 price) +{ + childSetValue("price_for_listing", price); +} + void LLPanelClassifiedEdit::onSetLocationClick() { setPosGlobal(gAgent.getPositionGlobal()); @@ -1855,18 +2079,51 @@ void LLPanelClassifiedEdit::onSaveClick() notifyInvalidName(); return; } - if(isNew()) + if(isNew() || isNewWithErrors()) { if(gStatusBar->getBalance() < getPriceForListing()) { LLNotificationsUtil::add("ClassifiedInsufficientFunds"); return; } + + mPublishFloater = LLFloaterReg::findTypedInstance<LLPublishClassifiedFloater>( + "publish_classified", LLSD()); + + if(!mPublishFloater) + { + mPublishFloater = LLFloaterReg::getTypedInstance<LLPublishClassifiedFloater>( + "publish_classified", LLSD()); + + mPublishFloater->setPublishClickedCallback(boost::bind + (&LLPanelClassifiedEdit::onPublishFloaterPublishClicked, this)); + } + + // set spinner value before it has focus or value wont be set + mPublishFloater->setPrice(getPriceForListing()); + mPublishFloater->openFloater(mPublishFloater->getKey()); + mPublishFloater->center(); } + else + { + doSave(); + } +} +void LLPanelClassifiedEdit::doSave() +{ mCanClose = true; sendUpdate(); resetDirty(); + + mSaveButtonClickedSignal(this, LLSD()); +} + +void LLPanelClassifiedEdit::onPublishFloaterPublishClicked() +{ + setPriceForListing(mPublishFloater->getPrice()); + + doSave(); } std::string LLPanelClassifiedEdit::getLocationNotice() @@ -1913,4 +2170,52 @@ void LLPanelClassifiedEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl) ctrl->setVisible(FALSE); } +void LLPanelClassifiedEdit::onTextureSelected() +{ + setSnapshotId(mSnapshotCtrl->getValue().asUUID()); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPublishClassifiedFloater::LLPublishClassifiedFloater(const LLSD& key) + : LLFloater(key) +{ +} + +LLPublishClassifiedFloater::~LLPublishClassifiedFloater() +{ +} + +BOOL LLPublishClassifiedFloater::postBuild() +{ + LLFloater::postBuild(); + + childSetAction("publish_btn", boost::bind(&LLFloater::closeFloater, this, false)); + childSetAction("cancel_btn", boost::bind(&LLFloater::closeFloater, this, false)); + + return TRUE; +} + +void LLPublishClassifiedFloater::setPrice(S32 price) +{ + childSetValue("price_for_listing", price); +} + +S32 LLPublishClassifiedFloater::getPrice() +{ + return childGetValue("price_for_listing").asInteger(); +} + +void LLPublishClassifiedFloater::setPublishClickedCallback(const commit_signal_t::slot_type& cb) +{ + getChild<LLButton>("publish_btn")->setClickedCallback(cb); +} + +void LLPublishClassifiedFloater::setCancelClickedCallback(const commit_signal_t::slot_type& cb) +{ + getChild<LLButton>("cancel_btn")->setClickedCallback(cb); +} + //EOF |