diff options
Diffstat (limited to 'indra/llui')
39 files changed, 433 insertions, 192 deletions
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index b91c614424..7721137e29 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -32,6 +32,7 @@ #include "linden_common.h" +#define LLBUTTON_CPP #include "llbutton.h" // Linden library includes @@ -56,6 +57,10 @@ static LLDefaultChildRegistry::Register<LLButton> r("button"); +// Compiler optimization, generate extern template +template class LLButton* LLView::getChild<class LLButton>( + const std::string& name, BOOL recurse) const; + // globals loaded from settings.xml S32 LLBUTTON_H_PAD = 0; S32 LLBUTTON_V_PAD = 0; diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 8c3b4bd859..4c7400220d 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -322,5 +322,10 @@ private: LLFrameTimer mFlashingTimer; }; +// Build time optimization, generate once in .cpp file +#ifndef LLBUTTON_CPP +extern template class LLButton* LLView::getChild<class LLButton>( + const std::string& name, BOOL recurse) const; +#endif #endif // LL_LLBUTTON_H diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index 7f0f9751db..cd10dfdb1c 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -33,6 +33,7 @@ // The mutants are coming! #include "linden_common.h" +#define LLCHECKBOXCTRL_CPP #include "llcheckboxctrl.h" #include "llgl.h" @@ -50,6 +51,10 @@ const U32 MAX_STRING_LENGTH = 10; static LLDefaultChildRegistry::Register<LLCheckBoxCtrl> r("check_box"); +// Compiler optimization, generate extern template +template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>( + const std::string& name, BOOL recurse) const; + LLCheckBoxCtrl::Params::Params() : text_enabled_color("text_enabled_color"), text_disabled_color("text_disabled_color"), diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index b14e66b915..28d50f957d 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -126,5 +126,10 @@ protected: LLUIColor mTextDisabledColor; }; +// Build time optimization, generate once in .cpp file +#ifndef LLCHECKBOXCTRL_CPP +extern template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>( + const std::string& name, BOOL recurse) const; +#endif #endif // LL_LLCHECKBOXCTRL_H diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index ddfb0f8534..831ac66d06 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -39,8 +39,8 @@ static const LLDefaultChildRegistry::Register<LLFlatListView> flat_list_view("flat_list_view"); -const LLSD SELECTED_EVENT = LLSD().insert("selected", true); -const LLSD UNSELECTED_EVENT = LLSD().insert("selected", false); +const LLSD SELECTED_EVENT = LLSD().with("selected", true); +const LLSD UNSELECTED_EVENT = LLSD().with("selected", false); static const std::string COMMENT_TEXTBOX = "comment_text"; @@ -530,7 +530,7 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) if ( !selectNextItemPair(true, reset_selection) && reset_selection) { // If case we are in accordion tab notify parent to go to the previous accordion - notifyParent(LLSD().insert("action","select_prev")); + notifyParent(LLSD().with("action","select_prev")); } break; } @@ -539,7 +539,7 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) if ( !selectNextItemPair(false, reset_selection) && reset_selection) { // If case we are in accordion tab notify parent to go to the next accordion - notifyParent(LLSD().insert("action","select_next")); + notifyParent(LLSD().with("action","select_next")); } break; } @@ -570,7 +570,7 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) // In case we are in accordion tab notify parent to show selected rectangle LLRect screen_rc; localRectToScreen(selected_rc, &screen_rc); - notifyParent(LLSD().insert("scrollToShowRect",screen_rc.getValue())); + notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue())); handled = TRUE; } @@ -689,6 +689,17 @@ LLRect LLFlatListView::getSelectedItemsRect() return rc; } +void LLFlatListView::selectFirstItem () +{ + selectItemPair(mItemPairs.front(), true); +} + +void LLFlatListView::selectLastItem () +{ + selectItemPair(mItemPairs.back(), true); +} + + // virtual bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selection) { @@ -696,53 +707,53 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti if ( !mItemPairs.size() ) return false; - item_pair_t* cur_sel_pair = NULL; + item_pair_t* to_sel_pair = NULL; - + item_pair_t* cur_sel_pair = NULL; if ( mSelectedItemPairs.size() ) { // Take the last selected pair cur_sel_pair = mSelectedItemPairs.back(); - } - else - { - // If there weren't selected items then choose the first one bases on given direction - cur_sel_pair = (is_up_direction) ? mItemPairs.back() : mItemPairs.front(); - // Force selection to first item - to_sel_pair = cur_sel_pair; - } - - // Bases on given direction choose next item to select - if ( is_up_direction ) - { - // Find current selected item position in mItemPairs list - pairs_list_t::reverse_iterator sel_it = std::find(mItemPairs.rbegin(), mItemPairs.rend(), cur_sel_pair); - - for (;++sel_it != mItemPairs.rend();) + // Bases on given direction choose next item to select + if ( is_up_direction ) { - // skip invisible items - if ( (*sel_it)->first->getVisible() ) + // Find current selected item position in mItemPairs list + pairs_list_t::reverse_iterator sel_it = std::find(mItemPairs.rbegin(), mItemPairs.rend(), cur_sel_pair); + + for (;++sel_it != mItemPairs.rend();) { - to_sel_pair = *sel_it; - break; + // skip invisible items + if ( (*sel_it)->first->getVisible() ) + { + to_sel_pair = *sel_it; + break; + } } } - } - else - { - // Find current selected item position in mItemPairs list - pairs_list_t::iterator sel_it = std::find(mItemPairs.begin(), mItemPairs.end(), cur_sel_pair); - - for (;++sel_it != mItemPairs.end();) + else { - // skip invisible items - if ( (*sel_it)->first->getVisible() ) + // Find current selected item position in mItemPairs list + pairs_list_t::iterator sel_it = std::find(mItemPairs.begin(), mItemPairs.end(), cur_sel_pair); + + for (;++sel_it != mItemPairs.end();) { - to_sel_pair = *sel_it; - break; + // skip invisible items + if ( (*sel_it)->first->getVisible() ) + { + to_sel_pair = *sel_it; + break; + } } } } + else + { + // If there weren't selected items then choose the first one bases on given direction + cur_sel_pair = (is_up_direction) ? mItemPairs.back() : mItemPairs.front(); + // Force selection to first item + to_sel_pair = cur_sel_pair; + } + if ( to_sel_pair ) { @@ -920,4 +931,26 @@ void LLFlatListView::onFocusLost() mSelectedItemsBorder->setVisible(FALSE); } +//virtual +S32 LLFlatListView::notify(const LLSD& info) +{ + if(info.has("action")) + { + std::string str_action = info["action"]; + if(str_action == "select_first") + { + setFocus(true); + selectFirstItem(); + return 1; + } + else if(str_action == "select_last") + { + setFocus(true); + selectLastItem(); + return 1; + } + } + return 0; +} + //EOF diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 3867e910c0..ba824ff2df 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -279,6 +279,12 @@ public: bool updateValue(const LLSD& old_value, const LLSD& new_value); + + void selectFirstItem (); + void selectLastItem (); + + virtual S32 notify(const LLSD& info) ; + protected: /** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */ diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 8cf65fe76a..fd7b64af02 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -74,7 +74,6 @@ std::string LLFloater::sButtonNames[BUTTON_COUNT] = "llfloater_minimize_btn", //BUTTON_MINIMIZE "llfloater_tear_off_btn", //BUTTON_TEAR_OFF "llfloater_dock_btn", //BUTTON_DOCK - "llfloater_undock_btn", //BUTTON_UNDOCK "llfloater_help_btn" //BUTTON_HELP }; @@ -91,7 +90,6 @@ std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]= "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF "BUTTON_DOCK", - "BUTTON_UNDOCK", "BUTTON_HELP" }; @@ -102,7 +100,6 @@ LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] = LLFloater::onClickMinimize, //BUTTON_MINIMIZE LLFloater::onClickTearOff, //BUTTON_TEAR_OFF LLFloater::onClickDock, //BUTTON_DOCK - LLFloater::onClickDock, //BUTTON_UNDOCK LLFloater::onClickHelp //BUTTON_HELP }; @@ -179,14 +176,12 @@ LLFloater::Params::Params() minimize_image("minimize_image"), tear_off_image("tear_off_image"), dock_image("dock_image"), - undock_image("undock_image"), help_image("help_image"), close_pressed_image("close_pressed_image"), restore_pressed_image("restore_pressed_image"), minimize_pressed_image("minimize_pressed_image"), tear_off_pressed_image("tear_off_pressed_image"), dock_pressed_image("dock_pressed_image"), - undock_pressed_image("undock_pressed_image"), help_pressed_image("help_pressed_image"), open_callback("open_callback"), close_callback("close_callback") @@ -1395,12 +1390,10 @@ void LLFloater::setCanDock(bool b) if(mCanDock) { mButtonsEnabled[BUTTON_DOCK] = !mDocked; - mButtonsEnabled[BUTTON_UNDOCK] = mDocked; } else { mButtonsEnabled[BUTTON_DOCK] = FALSE; - mButtonsEnabled[BUTTON_UNDOCK] = FALSE; } } updateButtons(); @@ -1412,7 +1405,6 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock) { mDocked = docked; mButtonsEnabled[BUTTON_DOCK] = !mDocked; - mButtonsEnabled[BUTTON_UNDOCK] = mDocked; updateButtons(); storeDockStateControl(); @@ -1452,6 +1444,7 @@ void LLFloater::onClickTearOff(LLFloater* self) gFloaterView->adjustToFitScreen(self, FALSE); // give focus to new window to keep continuity for the user self->setFocus(TRUE); + self->setTornOff(true); } else //Attach to parent. { @@ -1463,6 +1456,7 @@ void LLFloater::onClickTearOff(LLFloater* self) // make sure host is visible new_host->openFloater(new_host->getKey()); } + self->setTornOff(false); } } @@ -1862,8 +1856,6 @@ LLUIImage* LLFloater::getButtonImage(const Params& p, EFloaterButton e) return p.tear_off_image; case BUTTON_DOCK: return p.dock_image; - case BUTTON_UNDOCK: - return p.undock_image; case BUTTON_HELP: return p.help_image; } @@ -1885,8 +1877,6 @@ LLUIImage* LLFloater::getButtonPressedImage(const Params& p, EFloaterButton e) return p.tear_off_pressed_image; case BUTTON_DOCK: return p.dock_pressed_image; - case BUTTON_UNDOCK: - return p.undock_pressed_image; case BUTTON_HELP: return p.help_pressed_image; } @@ -2347,8 +2337,7 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out } LLRect::tCoordType screen_width = getSnapRect().getWidth(); LLRect::tCoordType screen_height = getSnapRect().getHeight(); - // convert to local coordinate frame - LLRect snap_rect_local = getLocalSnapRect(); + // only automatically resize non-minimized, resizable floaters if( floater->isResizable() && !floater->isMinimized() ) @@ -2388,7 +2377,7 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out } // move window fully onscreen - if (floater->translateIntoRect( snap_rect_local, allow_partial_outside )) + if (floater->translateIntoRect( getLocalRect(), allow_partial_outside )) { floater->clearSnapTarget(); } diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index d7ec0aac00..daf558de24 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -90,7 +90,6 @@ public: BUTTON_MINIMIZE, BUTTON_TEAR_OFF, BUTTON_DOCK, - BUTTON_UNDOCK, BUTTON_HELP, BUTTON_COUNT }; @@ -121,14 +120,12 @@ public: minimize_image, tear_off_image, dock_image, - undock_image, help_image; Optional<LLUIImage*> close_pressed_image, restore_pressed_image, minimize_pressed_image, tear_off_pressed_image, dock_pressed_image, - undock_pressed_image, help_pressed_image; Optional<CommitCallbackParam> open_callback, @@ -259,6 +256,8 @@ public: bool isDocked() const { return mDocked; } virtual void setDocked(bool docked, bool pop_on_undock = true); + virtual void setTornOff(bool torn_off) {} + // Return a closeable floater, if any, given the current focus. static LLFloater* getClosableFloaterFromFocus(); diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp index 029d3b6810..082d7c1573 100644 --- a/indra/llui/llfloaterreglistener.cpp +++ b/indra/llui/llfloaterreglistener.cpp @@ -28,7 +28,7 @@ LLFloaterRegListener::LLFloaterRegListener(): add("getBuildMap", "Return on [\"reply\"] data about all registered LLFloaterReg floater names", &LLFloaterRegListener::getBuildMap, - LLSD().insert("reply", LLSD())); + LLSD().with("reply", LLSD())); LLSD requiredName; requiredName["name"] = LLSD(); add("showInstance", diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 4ea30dbd4d..8a21155cc3 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -34,6 +34,7 @@ #include "linden_common.h" +#define LLLINEEDITOR_CPP #include "lllineeditor.h" #include "lltexteditor.h" @@ -71,6 +72,10 @@ const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click static LLDefaultChildRegistry::Register<LLLineEditor> r1("line_editor"); +// Compiler optimization, generate extern template +template class LLLineEditor* LLView::getChild<class LLLineEditor>( + const std::string& name, BOOL recurse) const; + // // Member functions // diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index b96220e020..49e9539b16 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -395,5 +395,10 @@ private: }; // end class LLLineEditor +// Build time optimization, generate once in .cpp file +#ifndef LLLINEEDITOR_CPP +extern template class LLLineEditor* LLView::getChild<class LLLineEditor>( + const std::string& name, BOOL recurse) const; +#endif #endif // LL_LINEEDITOR_ diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index f8935d03ac..907f2352a0 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -590,12 +590,13 @@ BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask) LLMenuGL* parent_menu = getMenu(); if (y > getRect().getHeight() / 2) { - LLView* prev_menu_item = parent_menu->findPrevSibling(this); + // the menu items are in the child list in bottom up order + LLView* prev_menu_item = parent_menu->findNextSibling(this); return prev_menu_item ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; } else { - LLView* next_menu_item = parent_menu->findNextSibling(this); + LLView* next_menu_item = parent_menu->findPrevSibling(this); return next_menu_item ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE; } } @@ -605,12 +606,12 @@ BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask) LLMenuGL* parent_menu = getMenu(); if (y > getRect().getHeight() / 2) { - LLView* prev_menu_item = parent_menu->findPrevSibling(this); + LLView* prev_menu_item = parent_menu->findNextSibling(this); return prev_menu_item ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; } else { - LLView* next_menu_item = parent_menu->findNextSibling(this); + LLView* next_menu_item = parent_menu->findPrevSibling(this); return next_menu_item ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE; } } diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 05f2d3a9cf..86989012ee 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -711,7 +711,7 @@ LLBoundListener LLNotificationChannelBase::connectChangedImpl(const LLEventListe // only about new notifications for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) { - slot(LLSD().insert("sigtype", "load").insert("id", (*it)->id())); + slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); } // and then connect the signal so that all future notifications will also be // forwarded. @@ -722,7 +722,7 @@ LLBoundListener LLNotificationChannelBase::connectAtFrontChangedImpl(const LLEve { for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) { - slot(LLSD().insert("sigtype", "load").insert("id", (*it)->id())); + slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); } return mChanged.connect(slot, boost::signals2::at_front); } @@ -907,7 +907,7 @@ void LLNotificationChannel::setComparator(LLNotificationComparator comparator) mItems.swap(s2); // notify clients that we've been resorted - mChanged(LLSD().insert("sigtype", "sort")); + mChanged(LLSD().with("sigtype", "sort")); } bool LLNotificationChannel::isEmpty() const @@ -1443,7 +1443,7 @@ void LLNotifications::add(const LLNotificationPtr pNotif) llerrs << "Notification added a second time to the master notification channel." << llendl; } - updateItem(LLSD().insert("sigtype", "add").insert("id", pNotif->id()), pNotif); + updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif); } void LLNotifications::cancel(LLNotificationPtr pNotif) @@ -1454,7 +1454,7 @@ void LLNotifications::cancel(LLNotificationPtr pNotif) llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl; } pNotif->cancel(); - updateItem(LLSD().insert("sigtype", "delete").insert("id", pNotif->id()), pNotif); + updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); } void LLNotifications::update(const LLNotificationPtr pNotif) @@ -1462,7 +1462,7 @@ void LLNotifications::update(const LLNotificationPtr pNotif) LLNotificationSet::iterator it=mItems.find(pNotif); if (it != mItems.end()) { - updateItem(LLSD().insert("sigtype", "change").insert("id", pNotif->id()), pNotif); + updateItem(LLSD().with("sigtype", "change").with("id", pNotif->id()), pNotif); } } diff --git a/indra/llui/llnotificationsutil.cpp b/indra/llui/llnotificationsutil.cpp index 2cd165f1b3..f343d27cb4 100644 --- a/indra/llui/llnotificationsutil.cpp +++ b/indra/llui/llnotificationsutil.cpp @@ -89,3 +89,8 @@ S32 LLNotificationsUtil::getSelectedOption(const LLSD& notification, const LLSD& { return LLNotification::getSelectedOption(notification, response); } + +void LLNotificationsUtil::cancel(LLNotificationPtr pNotif) +{ + LLNotifications::instance().cancel(pNotif); +} diff --git a/indra/llui/llnotificationsutil.h b/indra/llui/llnotificationsutil.h index a0801b338f..d552fa915b 100644 --- a/indra/llui/llnotificationsutil.h +++ b/indra/llui/llnotificationsutil.h @@ -63,6 +63,8 @@ namespace LLNotificationsUtil boost::function<void (const LLSD&, const LLSD&)> functor); S32 getSelectedOption(const LLSD& notification, const LLSD& response); + + void cancel(LLNotificationPtr pNotif); } #endif diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 063822dd56..750b190953 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -34,6 +34,7 @@ #include "linden_common.h" +#define LLPANEL_CPP #include "llpanel.h" #include "llalertdialog.h" @@ -58,6 +59,10 @@ static LLDefaultChildRegistry::Register<LLPanel> r1("panel", &LLPanel::fromXML); +// Compiler optimization, generate extern template +template class LLPanel* LLView::getChild<class LLPanel>( + const std::string& name, BOOL recurse) const; + LLPanel::LocalizedString::LocalizedString() : name("name"), value("value") diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index 0a0fed82fb..a8bd5fd5e5 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -275,4 +275,10 @@ private: }; // end class LLPanel +// Build time optimization, generate once in .cpp file +#ifndef LLPANEL_CPP +extern template class LLPanel* LLView::getChild<class LLPanel>( + const std::string& name, BOOL recurse) const; +#endif + #endif diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index d91b58b4ea..a5e47e8547 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -111,8 +111,7 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p) LLView::addChild( mBorder ); mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - if ( mBorder->getVisible() ) - mInnerRect.stretch( -mBorder->getBorderWidth() ); + mInnerRect.stretch( -getBorderWidth() ); LLRect vertical_scroll_rect = mInnerRect; vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - scrollbar_size; @@ -190,8 +189,7 @@ void LLScrollContainer::reshape(S32 width, S32 height, LLUICtrl::reshape( width, height, called_from_parent ); mInnerRect = getLocalRect(); - if ( mBorder->getVisible() ) - mInnerRect.stretch( -mBorder->getBorderWidth() ); + mInnerRect.stretch( -getBorderWidth() ); if (mScrolledView) { @@ -237,18 +235,37 @@ BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask) BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks ) { - if(LLUICtrl::handleScrollWheel(x,y,clicks)) + // Give event to my child views - they may have scroll bars + // (Bad UI design, but technically possible.) + if (LLUICtrl::handleScrollWheel(x,y,clicks)) return TRUE; - for( S32 i = 0; i < SCROLLBAR_COUNT; i++ ) - { - // Note: tries vertical and then horizontal + // When the vertical scrollbar is visible, scroll wheel + // only affects vertical scrolling. It's confusing to have + // scroll wheel perform both vertical and horizontal in a + // single container. + LLScrollbar* vertical = mScrollbar[VERTICAL]; + if (vertical->getVisible() + && vertical->getEnabled()) + { // Pretend the mouse is over the scrollbar - if( mScrollbar[i]->handleScrollWheel( 0, 0, clicks ) ) + if (vertical->handleScrollWheel( 0, 0, clicks ) ) { updateScroll(); - return TRUE; } + // Always eat the event + return TRUE; + } + + LLScrollbar* horizontal = mScrollbar[HORIZONTAL]; + // Test enablement and visibility for consistency with + // LLView::childrenHandleScrollWheel(). + if (horizontal->getVisible() + && horizontal->getEnabled() + && horizontal->handleScrollWheel( 0, 0, clicks ) ) + { + updateScroll(); + return TRUE; } return FALSE; } @@ -353,9 +370,9 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height S32 doc_width = doc_rect.getWidth(); S32 doc_height = doc_rect.getHeight(); - S32 border_width = (mBorder->getVisible() ? 2 * mBorder->getBorderWidth() : 0); - *visible_width = getRect().getWidth() - border_width; - *visible_height = getRect().getHeight() - border_width; + S32 border_width = getBorderWidth(); + *visible_width = getRect().getWidth() - 2 * border_width; + *visible_height = getRect().getHeight() - 2 * border_width; *show_v_scrollbar = FALSE; *show_h_scrollbar = FALSE; @@ -501,7 +518,7 @@ void LLScrollContainer::updateScroll() BOOL show_h_scrollbar = FALSE; calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - S32 border_width = mBorder->getBorderWidth(); + S32 border_width = getBorderWidth(); if( show_v_scrollbar ) { if( doc_rect.mTop < getRect().getHeight() - border_width ) @@ -575,6 +592,9 @@ void LLScrollContainer::updateScroll() void LLScrollContainer::setBorderVisible(BOOL b) { mBorder->setVisible( b ); + // Recompute inner rect, as border visibility changes it + mInnerRect = getLocalRect(); + mInnerRect.stretch( -getBorderWidth() ); } LLRect LLScrollContainer::getVisibleContentRect() @@ -586,15 +606,16 @@ LLRect LLScrollContainer::getVisibleContentRect() return visible_rect; } -LLRect LLScrollContainer::getContentWindowRect() const +LLRect LLScrollContainer::getContentWindowRect() { + updateScroll(); LLRect scroller_view_rect; S32 visible_width = 0; S32 visible_height = 0; BOOL show_h_scrollbar = FALSE; BOOL show_v_scrollbar = FALSE; calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); - S32 border_width = mBorder->getVisible() ? mBorder->getBorderWidth() : 0; + S32 border_width = getBorderWidth(); scroller_view_rect.setOriginAndSize(border_width, show_h_scrollbar ? mScrollbar[HORIZONTAL]->getRect().mTop : border_width, visible_width, @@ -675,7 +696,7 @@ void LLScrollContainer::goToBottom() S32 LLScrollContainer::getBorderWidth() const { - if (mBorder) + if (mBorder->getVisible()) { return mBorder->getBorderWidth(); } diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index ac8ffe5258..25dcd071ab 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -96,7 +96,7 @@ public: void setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; } LLRect getVisibleContentRect(); - LLRect getContentWindowRect() const; + LLRect getContentWindowRect(); const LLRect& getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } void pageUp(S32 overlap = 0); void pageDown(S32 overlap = 0); diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index fad2b7bc99..6fa99df82e 100644 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -141,6 +141,15 @@ void LLSearchEditor::clear() } } +//virtual +void LLSearchEditor::setFocus( BOOL b ) +{ + if (mSearchEditor) + { + mSearchEditor->setFocus(b); + } +} + void LLSearchEditor::onClearButtonClick(const LLSD& data) { setText(LLStringUtil::null); diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index f395e7e816..bd2d595174 100644 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -83,6 +83,7 @@ public: virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); virtual void setLabel( const LLStringExplicit &new_label ); virtual void clear(); + virtual void setFocus( BOOL b ); void setKeystrokeCallback( commit_callback_t cb ) { mKeystrokeCallback = cb; } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 7bf10d774c..2a9515171a 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -156,6 +156,7 @@ LLTextBase::Params::Params() read_only("read_only", false), v_pad("v_pad", 0), h_pad("h_pad", 0), + clip_partial("clip_partial", true), line_spacing("line_spacing"), max_text_length("max_length", 255), font_shadow("font_shadow"), @@ -193,6 +194,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mHAlign(p.font_halign), mLineSpacingMult(p.line_spacing.multiple), mLineSpacingPixels(p.line_spacing.pixels), + mClipPartial(p.clip_partial && !p.allow_scroll), mTrackEnd( p.track_end ), mScrollIndex(-1), mSelectionStart( 0 ), @@ -379,10 +381,10 @@ void LLTextBase::drawSelectionBackground() // Draw the selection box (we're using a box instead of reversing the colors on the selected text). gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - const LLColor4& color = mReadOnly ? mReadOnlyBgColor.get() : mWriteableBgColor.get(); + const LLColor4& color = mReadOnly ? mReadOnlyFgColor.get() : mFgColor.get(); F32 alpha = hasFocus() ? 0.7f : 0.3f; alpha *= getDrawContext().mAlpha; - gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha ); + LLColor4 selection_color(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], alpha); for (std::vector<LLRect>::iterator rect_it = selection_rects.begin(); rect_it != selection_rects.end(); @@ -390,7 +392,7 @@ void LLTextBase::drawSelectionBackground() { LLRect selection_rect = *rect_it; selection_rect.translate(mTextRect.mLeft - content_display_rect.mLeft, mTextRect.mBottom - content_display_rect.mBottom); - gl_rect_2d(selection_rect); + gl_rect_2d(selection_rect, selection_color); } } } @@ -504,7 +506,7 @@ void LLTextBase::drawText() } LLRect scrolled_view_rect = getVisibleDocumentRect(); - std::pair<S32, S32> line_range = getVisibleLines(); + std::pair<S32, S32> line_range = getVisibleLines(mClipPartial); S32 first_line = line_range.first; S32 last_line = line_range.second; if (first_line >= last_line) @@ -524,25 +526,21 @@ void LLTextBase::drawText() for (S32 cur_line = first_line; cur_line < last_line; cur_line++) { + S32 next_line = cur_line + 1; line_info& line = mLineInfoList[cur_line]; - if ((line.mRect.mTop - scrolled_view_rect.mBottom) < mTextRect.mBottom) - { - break; - } - S32 next_start = -1; S32 line_end = text_len; - if ((cur_line + 1) < getLineCount()) + if (next_line < getLineCount()) { - next_start = getLineStart(cur_line + 1); + next_start = getLineStart(next_line); line_end = next_start; } LLRect text_rect(line.mRect.mLeft + mTextRect.mLeft - scrolled_view_rect.mLeft, line.mRect.mTop - scrolled_view_rect.mBottom + mTextRect.mBottom, - mDocumentView->getRect().getWidth() - scrolled_view_rect.mLeft, + llmin(mDocumentView->getRect().getWidth(), line.mRect.mRight) - scrolled_view_rect.mLeft, line.mRect.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom); // draw a single line of text @@ -562,6 +560,17 @@ void LLTextBase::drawText() } S32 clipped_end = llmin( line_end, cur_segment->getEnd() ) - cur_segment->getStart(); + + if (mUseEllipses + && clipped_end == line_end + && next_line == last_line + && last_line < (S32)mLineInfoList.size()) + { + // more text to go, but we can't fit it + // so attempt to draw one extra character to force ellipses + clipped_end++; + } + text_rect.mLeft = (S32)(cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect)); seg_start = clipped_end + cur_segment->getStart(); @@ -641,8 +650,6 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s if ( truncate() ) { - // The user's not getting everything he's hoping for - make_ui_sound("UISndBadKeystroke"); insert_len = getLength() - old_len; } @@ -1066,10 +1073,16 @@ void LLTextBase::reflow(S32 start_index) { mReflowNeeded = FALSE; + // shrink document to minimum size (visible portion of text widget) + // to force inlined widgets with follows set to shrink + mDocumentView->setShape(mTextRect); + bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false; LLRect old_cursor_rect = getLocalRectFromDocIndex(mCursorPos); bool follow_selection = mTextRect.overlaps(old_cursor_rect); // cursor is visible + old_cursor_rect.translate(-mTextRect.mLeft, -mTextRect.mBottom); + S32 first_line = getFirstVisibleLine(); // if scroll anchor not on first line, update it to first character of first line @@ -1080,6 +1093,8 @@ void LLTextBase::reflow(S32 start_index) mScrollIndex = mLineInfoList[first_line].mDocIndexStart; } LLRect first_char_rect = getLocalRectFromDocIndex(mScrollIndex); + // subtract off effect of horizontal scrollbar from local position of first char + first_char_rect.translate(-mTextRect.mLeft, -mTextRect.mBottom); S32 cur_top = 0; @@ -1178,6 +1193,10 @@ void LLTextBase::reflow(S32 start_index) ++seg_iter; seg_offset = 0; } + if (force_newline) + { + line_count++; + } } // calculate visible region for diplaying text @@ -1195,7 +1214,6 @@ void LLTextBase::reflow(S32 start_index) // apply scroll constraints after reflowing text if (!hasMouseCapture() && mScroller) { - LLRect visible_content_rect = getVisibleDocumentRect(); if (scrolled_to_bottom && mTrackEnd) { // keep bottom of text buffer visible @@ -1204,18 +1222,14 @@ void LLTextBase::reflow(S32 start_index) else if (hasSelection() && follow_selection) { // keep cursor in same vertical position on screen when selecting text - LLRect new_cursor_rect_doc = getLocalRectFromDocIndex(mCursorPos); - new_cursor_rect_doc.translate(visible_content_rect.mLeft, visible_content_rect.mBottom); + LLRect new_cursor_rect_doc = getDocRectFromDocIndex(mCursorPos); mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect); - //llassert_always(getLocalRectFromDocIndex(mCursorPos).mBottom == old_cursor_rect.mBottom); } else { // keep first line of text visible - LLRect new_first_char_rect = getLocalRectFromDocIndex(mScrollIndex); - new_first_char_rect.translate(visible_content_rect.mLeft, visible_content_rect.mBottom); + LLRect new_first_char_rect = getDocRectFromDocIndex(mScrollIndex); mScroller->scrollToShowRect(new_first_char_rect, first_char_rect); - //llassert_always(getLocalRectFromDocIndex(mScrollIndex).mBottom == first_char_rect.mBottom); } } @@ -1325,13 +1339,11 @@ std::pair<S32, S32> LLTextBase::getVisibleLines(bool fully_visible) if (fully_visible) { - // binary search for line that starts before top of visible buffer and starts before end of visible buffer first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_top()); last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_bottom()); } else { - // binary search for line that starts before top of visible buffer and starts before end of visible buffer first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom()); last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_top()); } @@ -1464,14 +1476,16 @@ void LLTextBase::setText(const LLStringExplicit &utf8str ,const LLStyle::Params& clearSegments(); // createDefaultSegment(); - startOfDoc(); deselect(); // append the new text (supports Url linking) std::string text(utf8str); LLStringUtil::removeCRLF(text); + // appendText modifies mCursorPos... appendText(text, false, input_params); + // ...so move cursor to top after appending text + startOfDoc(); onValueChange(0, getLength()); } @@ -2065,22 +2079,22 @@ void LLTextBase::updateRects() mContentsRect.unionWith(line_iter->mRect); } - S32 delta_pos_x = -mContentsRect.mLeft; mContentsRect.mTop += mVPad; S32 delta_pos = -mContentsRect.mBottom; // move line segments to fit new document rect for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) { - it->mRect.translate(delta_pos_x, delta_pos); + it->mRect.translate(0, delta_pos); } - mContentsRect.translate(delta_pos_x, delta_pos); + mContentsRect.translate(0, delta_pos); } // update document container dimensions according to text contents LLRect doc_rect = mContentsRect; // use old mTextRect constraint document to width of viewable region - doc_rect.mRight = doc_rect.mLeft + mTextRect.getWidth(); + doc_rect.mLeft = 0; + doc_rect.mRight = llmax(mTextRect.getWidth(), mContentsRect.mRight); mDocumentView->setShape(doc_rect); @@ -2100,7 +2114,7 @@ void LLTextBase::updateRects() } // update document container again, using new mTextRect - doc_rect.mRight = doc_rect.mLeft + mTextRect.getWidth(); + doc_rect.mRight = llmax(mTextRect.getWidth(), mContentsRect.mRight); mDocumentView->setShape(doc_rect); } @@ -2193,6 +2207,12 @@ LLNormalTextSegment::LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 mEditor(editor) { mFontHeight = llceil(mStyle->getFont()->getLineHeight()); + + LLUIImagePtr image = mStyle->getImage(); + if (image.notNull()) + { + mImageLoadedConnection = image->addLoadedCallback(boost::bind(&LLTextBase::needsReflow, &mEditor)); + } } LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) @@ -2205,6 +2225,12 @@ LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 mFontHeight = llceil(mStyle->getFont()->getLineHeight()); } +LLNormalTextSegment::~LLNormalTextSegment() +{ + mImageLoadedConnection.disconnect(); +} + + F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) { if( end - start > 0 ) @@ -2218,7 +2244,7 @@ F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selec // Center the image vertically S32 image_bottom = draw_rect.getCenterY() - (style_image_height/2); image->draw(draw_rect.mLeft, image_bottom, - style_image_width, style_image_height); + style_image_width, style_image_height, color); } return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect); @@ -2281,7 +2307,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele LLFontGL::LEFT, LLFontGL::TOP, 0, LLFontGL::NO_SHADOW, - length, rect.mRight, + length, rect.getWidth(), &right_x, mEditor.getUseEllipses()); } @@ -2298,7 +2324,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele LLFontGL::LEFT, LLFontGL::TOP, 0, mStyle->getShadowType(), - length, rect.mRight, + length, rect.getWidth(), &right_x, mEditor.getUseEllipses()); } @@ -2380,12 +2406,20 @@ void LLNormalTextSegment::setToolTip(const std::string& tooltip) bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { - LLWString text = mEditor.getWText(); - height = mFontHeight; - width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); - // if last character is a newline, then return true, forcing line break - llwchar last_char = text[mStart + first_char + num_chars - 1]; + bool force_newline = false; + if (num_chars > 0) + { + LLWString text = mEditor.getWText(); + width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); + // if last character is a newline, then return true, forcing line break + llwchar last_char = text[mStart + first_char + num_chars - 1]; + force_newline = (last_char == '\n'); + } + else + { + width = 0; + } LLUIImagePtr image = mStyle->getImage(); if( image.notNull()) @@ -2394,7 +2428,7 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt height = llmax(height, image->getHeight()); } - return num_chars >= 1 && last_char == '\n'; + return force_newline; } S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index c376a73615..0138ca3704 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -84,11 +84,13 @@ public: wrap, use_ellipses, allow_html, - parse_highlights; + parse_highlights, + clip_partial; Optional<S32> v_pad, h_pad; + Optional<LineSpacingParams> line_spacing; @@ -134,7 +136,6 @@ public: // TODO: move into LLTextSegment? void createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url - // Text accessors // TODO: add optional style parameter virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style @@ -146,6 +147,8 @@ public: LLWString getWText() const; void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params()); + // force reflow of text + void needsReflow() { mReflowNeeded = TRUE; } S32 getLength() const { return getWText().length(); } S32 getLineCount() const { return mLineInfoList.size(); } @@ -160,7 +163,6 @@ public: S32 getVPad() { return mVPad; } S32 getHPad() { return mHPad; } - S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const; LLRect getLocalRectFromDocIndex(S32 pos) const; LLRect getDocRectFromDocIndex(S32 pos) const; @@ -178,6 +180,7 @@ public: void changePage( S32 delta ); void changeLine( S32 delta ); + const LLFontGL* getDefaultFont() const { return mDefaultFont; } public: @@ -301,7 +304,6 @@ protected: // misc void updateRects(); - void needsReflow() { mReflowNeeded = TRUE; } void needsScroll() { mScrollNeeded = TRUE; } void replaceUrlLabel(const std::string &url, const std::string &label); @@ -347,6 +349,7 @@ protected: bool mTrackEnd; // if true, keeps scroll position at end of document during resize bool mReadOnly; bool mBGVisible; // render background? + bool mClipPartial; // false if we show lines that are partially inside bounding rect S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes // support widgets @@ -423,6 +426,7 @@ class LLNormalTextSegment : public LLTextSegment public: LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 end, LLTextBase& editor ); LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); + ~LLNormalTextSegment(); /*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const; /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; @@ -454,6 +458,7 @@ protected: S32 mFontHeight; LLKeywordToken* mToken; std::string mTooltip; + boost::signals2::connection mImageLoadedConnection; }; class LLIndexSegment : public LLTextSegment diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 4c4123cf45..0bd0ab59fb 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -31,7 +31,10 @@ */ #include "linden_common.h" + +#define LLTEXTBOX_CPP #include "lltextbox.h" + #include "lluictrlfactory.h" #include "llfocusmgr.h" #include "llwindow.h" @@ -40,6 +43,10 @@ static LLDefaultChildRegistry::Register<LLTextBox> r("text"); +// Compiler optimization, generate extern template +template class LLTextBox* LLView::getChild<class LLTextBox>( + const std::string& name, BOOL recurse) const; + LLTextBox::LLTextBox(const LLTextBox::Params& p) : LLTextBase(p), mClickedCallback(NULL) diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h index 01b4bfa5ed..3a045534d3 100644 --- a/indra/llui/lltextbox.h +++ b/indra/llui/lltextbox.h @@ -79,4 +79,10 @@ protected: callback_t mClickedCallback; }; +// Build time optimization, generate once in .cpp file +#ifndef LLTEXTBOX_CPP +extern template class LLTextBox* LLView::getChild<class LLTextBox>( + const std::string& name, BOOL recurse) const; +#endif + #endif diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3f4ef24f82..e68affc36c 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1,6 +1,5 @@ /** * @file lltexteditor.cpp - * @brief LLTextEditor base class * * $LicenseInfo:firstyear=2001&license=viewergpl$ * @@ -34,6 +33,7 @@ #include "linden_common.h" +#define LLTEXTEDITOR_CPP #include "lltexteditor.h" #include "llfontfreetype.h" // for LLFontFreetype::FIRST_CHAR @@ -73,6 +73,10 @@ // static LLDefaultChildRegistry::Register<LLTextEditor> r("simple_text_editor"); +// Compiler optimization, generate extern template +template class LLTextEditor* LLView::getChild<class LLTextEditor>( + const std::string& name, BOOL recurse) const; + // // Constants // @@ -2158,7 +2162,7 @@ void LLTextEditor::drawLineNumbers() return; } - S32 cursor_line = getLineNumFromDocIndex(mCursorPos); + S32 cursor_line = mLineInfoList[getLineNumFromDocIndex(mCursorPos)].mLineNum; if (mShowLineNumbers) { diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index fb014b86bf..043dda8fa6 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -334,5 +334,10 @@ private: LLContextMenu* mContextMenu; }; // end class LLTextEditor +// Build time optimization, generate once in .cpp file +#ifndef LLTEXTEDITOR_CPP +extern template class LLTextEditor* LLView::getChild<class LLTextEditor>( + const std::string& name, BOOL recurse) const; +#endif #endif // LL_TEXTEDITOR_ diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index d7228c78bd..01c7a81309 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -300,9 +300,8 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p) mTextBox->setText(p.message()); } - LLRect text_contents_rect = mTextBox->getContentsRect(); - S32 text_width = llmin(p.max_width(), text_contents_rect.getWidth()); - S32 text_height = text_contents_rect.getHeight(); + S32 text_width = llmin(p.max_width(), mTextBox->getTextPixelWidth()); + S32 text_height = mTextBox->getTextPixelHeight(); mTextBox->reshape(text_width, text_height); // reshape tooltip panel to fit text box diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 4cf503b413..6603887905 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -1847,8 +1847,8 @@ LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname) // spawn_x and spawn_y are top left corner of view in screen GL coordinates void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y) { - const S32 CURSOR_HEIGHT = 18; // Approximate "normal" cursor size - const S32 CURSOR_WIDTH = 9; + const S32 CURSOR_HEIGHT = 16; // Approximate "normal" cursor size + const S32 CURSOR_WIDTH = 8; LLView* parent = view->getParent(); @@ -1866,7 +1866,7 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y) LLRect virtual_window_rect = parent->getLocalRect(); LLRect mouse_rect; - const S32 MOUSE_CURSOR_PADDING = 5; + const S32 MOUSE_CURSOR_PADDING = 1; mouse_rect.setLeftTopAndSize(mouse_x - MOUSE_CURSOR_PADDING, mouse_y + MOUSE_CURSOR_PADDING, CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2, diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index a30d5b4651..706712ec5e 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -31,15 +31,43 @@ * $/LicenseInfo$ */ -//#include "llviewerprecompiledheaders.h" #include "linden_common.h" + +#define LLUICTRL_CPP #include "lluictrl.h" + #include "llfocusmgr.h" #include "llpanel.h" #include "lluictrlfactory.h" static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl"); +// Compiler optimization, generate extern template +template class LLUICtrl* LLView::getChild<class LLUICtrl>( + const std::string& name, BOOL recurse) const; + +LLUICtrl::CallbackParam::CallbackParam() +: name("name"), + function_name("function"), + parameter("parameter"), + control_name("control") // Shortcut to control -> "control_name" for backwards compatability +{ + addSynonym(parameter, "userdata"); +} + +LLUICtrl::EnableControls::EnableControls() +: enabled("enabled_control"), + disabled("disabled_control") +{} + +LLUICtrl::ControlVisibility::ControlVisibility() +: visible("visibility_control"), + invisible("invisibility_control") +{ + addSynonym(visible, "visiblity_control"); + addSynonym(invisible, "invisiblity_control"); +} + LLUICtrl::Params::Params() : tab_stop("tab_stop", true), chrome("chrome", false), diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index aef1bcd519..b20ff5d798 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -75,14 +75,7 @@ public: Optional<std::string> control_name; - CallbackParam() - : name("name"), - function_name("function"), - parameter("parameter"), - control_name("control") // Shortcut to control -> "control_name" for backwards compatability - { - addSynonym(parameter, "userdata"); - } + CallbackParam(); }; struct CommitCallbackParam : public LLInitParam::Block<CommitCallbackParam, CallbackParam > @@ -105,23 +98,14 @@ public: Alternative<std::string> enabled; Alternative<std::string> disabled; - EnableControls() - : enabled("enabled_control"), - disabled("disabled_control") - {} + EnableControls(); }; struct ControlVisibility : public LLInitParam::Choice<ControlVisibility> { Alternative<std::string> visible; Alternative<std::string> invisible; - ControlVisibility() - : visible("visibility_control"), - invisible("invisibility_control") - { - addSynonym(visible, "visiblity_control"); - addSynonym(invisible, "invisiblity_control"); - } + ControlVisibility(); }; struct Params : public LLInitParam::Block<Params, LLView::Params> { @@ -328,4 +312,10 @@ private: class DefaultTabGroupFirstSorter; }; +// Build time optimization, generate once in .cpp file +#ifndef LLUICTRL_CPP +extern template class LLUICtrl* LLView::getChild<class LLUICtrl>( + const std::string& name, BOOL recurse) const; +#endif + #endif // LL_LLUICTRL_H diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 1c1450d7e9..3643bf44f7 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -32,6 +32,7 @@ #include "linden_common.h" +#define LLUICTRLFACTORY_CPP #include "lluictrlfactory.h" #include "llxmlnode.h" @@ -75,6 +76,9 @@ public: static LLDefaultChildRegistry::Register<LLUICtrlLocate> r1("locate"); +// Build time optimization, generate this once in .cpp file +template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getInstance(); + //----------------------------------------------------------------------------- // LLUICtrlFactory() //----------------------------------------------------------------------------- diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 8a9c9e23c1..55d7d745eb 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -108,6 +108,11 @@ extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP; extern LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION; extern LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS; +// Build time optimization, generate this once in .cpp file +#ifndef LLUICTRLFACTORY_CPP +extern template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getInstance(); +#endif + class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory> { private: diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp index a8683e55c3..f941f391eb 100644 --- a/indra/llui/lluiimage.cpp +++ b/indra/llui/lluiimage.cpp @@ -39,18 +39,20 @@ #include "lluiimage.h" #include "llui.h" -LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image) : - mName(name), - mImage(image), - mScaleRegion(0.f, 1.f, 1.f, 0.f), - mClipRegion(0.f, 1.f, 1.f, 0.f), - mUniformScaling(TRUE), - mNoClip(TRUE) +LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image) +: mName(name), + mImage(image), + mScaleRegion(0.f, 1.f, 1.f, 0.f), + mClipRegion(0.f, 1.f, 1.f, 0.f), + mUniformScaling(TRUE), + mNoClip(TRUE), + mImageLoaded(NULL) { } LLUIImage::~LLUIImage() { + delete mImageLoaded; } void LLUIImage::setClipRegion(const LLRectf& region) @@ -138,6 +140,25 @@ S32 LLUIImage::getTextureHeight() const return mImage->getHeight(0); } +boost::signals2::connection LLUIImage::addLoadedCallback( const image_loaded_signal_t::slot_type& cb ) +{ + if (!mImageLoaded) + { + mImageLoaded = new image_loaded_signal_t(); + } + return mImageLoaded->connect(cb); +} + + +void LLUIImage::onImageLoaded() +{ + if (mImageLoaded) + { + (*mImageLoaded)(); + } +} + + namespace LLInitParam { LLUIImage* TypedParam<LLUIImage*>::getValueFromBlock() const @@ -170,3 +191,4 @@ namespace LLInitParam return (a == b); } } + diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h index 9d734bcfdf..5fa9610ab2 100644 --- a/indra/llui/lluiimage.h +++ b/indra/llui/lluiimage.h @@ -39,6 +39,7 @@ #include "llrefcount.h" #include "llrect.h" #include <boost/function.hpp> +#include <boost/signals2.hpp> #include "llinitparam.h" #include "lltexture.h" @@ -47,6 +48,8 @@ extern const LLColor4 UI_VERTEX_COLOR; class LLUIImage : public LLRefCount { public: + typedef boost::signals2::signal<void (void)> image_loaded_signal_t; + LLUIImage(const std::string& name, LLPointer<LLTexture> image); virtual ~LLUIImage(); @@ -77,7 +80,13 @@ public: S32 getTextureWidth() const; S32 getTextureHeight() const; + boost::signals2::connection addLoadedCallback( const image_loaded_signal_t::slot_type& cb ); + + void onImageLoaded(); + protected: + image_loaded_signal_t* mImageLoaded; + std::string mName; LLRectf mScaleRegion; LLRectf mClipRegion; diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index b51709e208..7694d02837 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -386,36 +386,24 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa // // LLUrlEntryInventory Describes a Second Life inventory Url, e.g., -// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select +// secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select // LLUrlEntryInventory::LLUrlEntryInventory() { - mPattern = boost::regex("secondlife:///app/inventory/[\\da-f-]+/\\w+", + //*TODO: add supporting of inventory item names with whitespaces + //this pattern cann't parse for example + //secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value + mPattern = boost::regex("secondlife:///app/inventory/[\\da-f-]+/\\w+\\S*", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_inventory.xml"; } std::string LLUrlEntryInventory::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - return unescapeUrl(url); - // TODO: Figure out if we can somehow access the inventory from here to get the actual item name - /* - std::string inventory_id_string = getIDStringFromUrl(url); - if (inventory_id_string.empty()) - { - // something went wrong, give raw url - return unescapeUrl(url); - } - LLUUID inventory_id(inventory_id_string); - LLInventoryItem* item = gInventory.getItem(inventory_id); - if(!item) - { - return unescapeUrl(url); - } - return item->getName(); */ + std::string label = getStringAfterToken(url, "name="); + return LLURI::unescape(label.empty() ? url : label); } - /// /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index b2f084e5ac..f47db2db1a 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -53,9 +53,11 @@ LLUrlRegistry::LLUrlRegistry() registerUrl(new LLUrlEntryTeleport()); registerUrl(new LLUrlEntryWorldMap()); registerUrl(new LLUrlEntryPlace()); + registerUrl(new LLUrlEntryInventory()); + //LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern, + //so it should be registered in the end of list registerUrl(new LLUrlEntrySL()); registerUrl(new LLUrlEntrySLLabel()); - registerUrl(new LLUrlEntryInventory()); } LLUrlRegistry::~LLUrlRegistry() diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index dba24ee165..8917e4b813 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -33,6 +33,7 @@ #include "linden_common.h" +#define LLVIEW_CPP #include "llview.h" #include <cassert> @@ -76,8 +77,17 @@ std::vector<LLViewDrawContext*> LLViewDrawContext::sDrawContextStack; BOOL LLView::sIsDrawing = FALSE; #endif +// Compiler optimization, generate extern template +template class LLView* LLView::getChild<class LLView>( + const std::string& name, BOOL recurse) const; + static LLDefaultChildRegistry::Register<LLView> r("view"); +LLView::Follows::Follows() +: string(""), + flags("flags", FOLLOWS_LEFT | FOLLOWS_TOP) +{} + LLView::Params::Params() : name("name", std::string("unnamed")), enabled("enabled", true), @@ -2523,6 +2533,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) else { p.rect.left = p.rect.left + parent_rect.getWidth()/2 - p.rect.width/2; + p.rect.right.setProvided(false); // recalculate the right } } else @@ -2543,6 +2554,7 @@ void LLView::setupParams(LLView::Params& p, LLView* parent) else { p.rect.bottom = p.rect.bottom + parent_rect.getHeight()/2 - p.rect.height/2; + p.rect.top.setProvided(false); // recalculate the top } } else @@ -2838,18 +2850,21 @@ LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const return *mDefaultWidgets; } -void LLView::notifyParent(const LLSD& info) +S32 LLView::notifyParent(const LLSD& info) { LLView* parent = getParent(); if(parent) - parent->notifyParent(info); + return parent->notifyParent(info); + return 0; } -void LLView::notifyChildren(const LLSD& info) +bool LLView::notifyChildren(const LLSD& info) { + bool ret = false; for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) { - (*child_it)->notifyChildren(info); + ret |= (*child_it)->notifyChildren(info); } + return ret; } // convenient accessor for draw context diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 2607120e17..f8460f5361 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -111,10 +111,7 @@ public: Alternative<std::string> string; Alternative<U32> flags; - Follows() - : string(""), - flags("flags", FOLLOWS_LEFT | FOLLOWS_TOP) - {} + Follows(); }; struct Params : public LLInitParam::Block<Params> @@ -514,8 +511,15 @@ public: virtual void handleReshape(const LLRect& rect, bool by_user); virtual void dirtyRect(); - virtual void notifyParent(const LLSD& info); - virtual void notifyChildren(const LLSD& info); + //send custom notification to LLView parent + virtual S32 notifyParent(const LLSD& info); + + //send custom notification to all view childrend + // return true if _any_ children return true. otherwise false. + virtual bool notifyChildren(const LLSD& info); + + //send custom notification to current view + virtual S32 notify(const LLSD& info) { return 0;}; static const LLViewDrawContext& getDrawContext(); @@ -659,4 +663,11 @@ template <class T> T* LLView::getChild(const std::string& name, BOOL recurse) co return result; } +// Compiler optimization - don't generate these specializations inline, +// require explicit specialization. See llbutton.cpp for an example. +#ifndef LLVIEW_CPP +extern template class LLView* LLView::getChild<class LLView>( + const std::string& name, BOOL recurse) const; +#endif + #endif //LL_LLVIEW_H |