diff options
author | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
commit | cd17687f01420952712a500107e0f93e7ab8d5f8 (patch) | |
tree | ce48c2b706f2c1176290e39fb555fbdf6648ce01 /linden/indra/llui/lltabcontainer.cpp | |
parent | Second Life viewer sources 1.19.0.5 (diff) | |
download | meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.zip meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.gz meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.bz2 meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.xz |
Second Life viewer sources 1.19.1.0
Diffstat (limited to 'linden/indra/llui/lltabcontainer.cpp')
-rw-r--r-- | linden/indra/llui/lltabcontainer.cpp | 2397 |
1 files changed, 1268 insertions, 1129 deletions
diff --git a/linden/indra/llui/lltabcontainer.cpp b/linden/indra/llui/lltabcontainer.cpp index 0400b50..e632cf1 100644 --- a/linden/indra/llui/lltabcontainer.cpp +++ b/linden/indra/llui/lltabcontainer.cpp | |||
@@ -1,6 +1,6 @@ | |||
1 | /** | 1 | /** |
2 | * @file lltabcontainer.cpp | 2 | * @file lltabcontainer.cpp |
3 | * @brief LLTabContainerCommon base class | 3 | * @brief LLTabContainer class |
4 | * | 4 | * |
5 | * $LicenseInfo:firstyear=2001&license=viewergpl$ | 5 | * $LicenseInfo:firstyear=2001&license=viewergpl$ |
6 | * | 6 | * |
@@ -30,33 +30,24 @@ | |||
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include "linden_common.h" | 32 | #include "linden_common.h" |
33 | |||
34 | #include "lltabcontainer.h" | 33 | #include "lltabcontainer.h" |
35 | |||
36 | #include "llfocusmgr.h" | 34 | #include "llfocusmgr.h" |
37 | #include "llfontgl.h" | ||
38 | #include "llgl.h" | ||
39 | |||
40 | #include "llbutton.h" | 35 | #include "llbutton.h" |
41 | #include "llrect.h" | 36 | #include "llrect.h" |
42 | #include "llpanel.h" | ||
43 | #include "llresmgr.h" | 37 | #include "llresmgr.h" |
44 | #include "llkeyboard.h" | ||
45 | #include "llresizehandle.h" | 38 | #include "llresizehandle.h" |
46 | #include "llui.h" | ||
47 | #include "lltextbox.h" | 39 | #include "lltextbox.h" |
48 | #include "llcontrol.h" | ||
49 | #include "llcriticaldamp.h" | 40 | #include "llcriticaldamp.h" |
50 | #include "lluictrlfactory.h" | 41 | #include "lluictrlfactory.h" |
51 | |||
52 | #include "lltabcontainervertical.h" | 42 | #include "lltabcontainervertical.h" |
43 | #include "llglimmediate.h" | ||
53 | 44 | ||
54 | #include "llglheaders.h" | ||
55 | 45 | ||
56 | const F32 SCROLL_STEP_TIME = 0.4f; | 46 | const F32 SCROLL_STEP_TIME = 0.4f; |
57 | const F32 SCROLL_DELAY_TIME = 0.5f; | 47 | const F32 SCROLL_DELAY_TIME = 0.5f; |
58 | const S32 TAB_PADDING = 15; | 48 | const S32 TAB_PADDING = 15; |
59 | const S32 TABCNTR_TAB_MIN_WIDTH = 60; | 49 | const S32 TABCNTR_TAB_MIN_WIDTH = 60; |
50 | const S32 TABCNTR_VERT_TAB_MIN_WIDTH = 100; | ||
60 | const S32 TABCNTR_TAB_MAX_WIDTH = 150; | 51 | const S32 TABCNTR_TAB_MAX_WIDTH = 150; |
61 | const S32 TABCNTR_TAB_PARTIAL_WIDTH = 12; // When tabs are parially obscured, how much can you still see. | 52 | const S32 TABCNTR_TAB_PARTIAL_WIDTH = 12; // When tabs are parially obscured, how much can you still see. |
62 | const S32 TABCNTR_TAB_HEIGHT = 16; | 53 | const S32 TABCNTR_TAB_HEIGHT = 16; |
@@ -64,12 +55,19 @@ const S32 TABCNTR_ARROW_BTN_SIZE = 16; | |||
64 | const S32 TABCNTR_BUTTON_PANEL_OVERLAP = 1; // how many pixels the tab buttons and tab panels overlap. | 55 | const S32 TABCNTR_BUTTON_PANEL_OVERLAP = 1; // how many pixels the tab buttons and tab panels overlap. |
65 | const S32 TABCNTR_TAB_H_PAD = 4; | 56 | const S32 TABCNTR_TAB_H_PAD = 4; |
66 | 57 | ||
58 | const S32 TABCNTR_CLOSE_BTN_SIZE = 16; | ||
59 | const S32 TABCNTR_HEADER_HEIGHT = LLPANEL_BORDER_WIDTH + TABCNTR_CLOSE_BTN_SIZE; | ||
60 | |||
61 | const S32 TABCNTRV_CLOSE_BTN_SIZE = 16; | ||
62 | const S32 TABCNTRV_HEADER_HEIGHT = LLPANEL_BORDER_WIDTH + TABCNTRV_CLOSE_BTN_SIZE; | ||
63 | //const S32 TABCNTRV_TAB_WIDTH = 100; | ||
64 | const S32 TABCNTRV_ARROW_BTN_SIZE = 16; | ||
65 | const S32 TABCNTRV_PAD = 0; | ||
66 | |||
67 | 67 | ||
68 | LLTabContainerCommon::LLTabContainerCommon( | 68 | |
69 | const LLString& name, const LLRect& rect, | 69 | LLTabContainer::LLTabContainer(const LLString& name, const LLRect& rect, TabPosition pos, |
70 | TabPosition pos, | 70 | BOOL bordered, BOOL is_vertical ) |
71 | void(*close_callback)(void*), void* callback_userdata, | ||
72 | BOOL bordered ) | ||
73 | : | 71 | : |
74 | LLPanel(name, rect, bordered), | 72 | LLPanel(name, rect, bordered), |
75 | mCurrentTabIdx(-1), | 73 | mCurrentTabIdx(-1), |
@@ -78,50 +76,65 @@ LLTabContainerCommon::LLTabContainerCommon( | |||
78 | mScrollPos(0), | 76 | mScrollPos(0), |
79 | mScrollPosPixels(0), | 77 | mScrollPosPixels(0), |
80 | mMaxScrollPos(0), | 78 | mMaxScrollPos(0), |
81 | mCloseCallback( close_callback ), | 79 | mCloseCallback( NULL ), |
82 | mCallbackUserdata( callback_userdata ), | 80 | mCallbackUserdata( NULL ), |
83 | mTitleBox(NULL), | 81 | mTitleBox(NULL), |
84 | mTopBorderHeight(LLPANEL_BORDER_WIDTH), | 82 | mTopBorderHeight(LLPANEL_BORDER_WIDTH), |
85 | mTabPosition(pos), | 83 | mTabPosition(pos), |
86 | mLockedTabCount(0) | 84 | mLockedTabCount(0), |
85 | mMinTabWidth(TABCNTR_TAB_MIN_WIDTH), | ||
86 | mMaxTabWidth(TABCNTR_TAB_MAX_WIDTH), | ||
87 | mPrevArrowBtn(NULL), | ||
88 | mNextArrowBtn(NULL), | ||
89 | mIsVertical(is_vertical), | ||
90 | // Horizontal Specific | ||
91 | mJumpPrevArrowBtn(NULL), | ||
92 | mJumpNextArrowBtn(NULL), | ||
93 | mRightTabBtnOffset(0), | ||
94 | mTotalTabWidth(0) | ||
87 | { | 95 | { |
96 | //RN: HACK to support default min width for legacy vertical tab containers | ||
97 | if (mIsVertical) | ||
98 | { | ||
99 | mMinTabWidth = TABCNTR_VERT_TAB_MIN_WIDTH; | ||
100 | } | ||
88 | setMouseOpaque(FALSE); | 101 | setMouseOpaque(FALSE); |
102 | initButtons( ); | ||
89 | mDragAndDropDelayTimer.stop(); | 103 | mDragAndDropDelayTimer.stop(); |
90 | } | 104 | } |
91 | 105 | ||
106 | LLTabContainer::~LLTabContainer() | ||
107 | { | ||
108 | std::for_each(mTabList.begin(), mTabList.end(), DeletePointer()); | ||
109 | } | ||
92 | 110 | ||
93 | LLTabContainerCommon::LLTabContainerCommon( | 111 | //virtual |
94 | const LLString& name, | 112 | void LLTabContainer::setValue(const LLSD& value) |
95 | const LLString& rect_control, | ||
96 | TabPosition pos, | ||
97 | void(*close_callback)(void*), void* callback_userdata, | ||
98 | BOOL bordered ) | ||
99 | : | ||
100 | LLPanel(name, rect_control, bordered), | ||
101 | mCurrentTabIdx(-1), | ||
102 | mTabsHidden(FALSE), | ||
103 | mScrolled(FALSE), | ||
104 | mScrollPos(0), | ||
105 | mScrollPosPixels(0), | ||
106 | mMaxScrollPos(0), | ||
107 | mCloseCallback( close_callback ), | ||
108 | mCallbackUserdata( callback_userdata ), | ||
109 | mTitleBox(NULL), | ||
110 | mTopBorderHeight(LLPANEL_BORDER_WIDTH), | ||
111 | mTabPosition(pos), | ||
112 | mLockedTabCount(0) | ||
113 | { | 113 | { |
114 | setMouseOpaque(FALSE); | 114 | selectTab((S32) value.asInteger()); |
115 | mDragAndDropDelayTimer.stop(); | ||
116 | } | 115 | } |
117 | 116 | ||
117 | //virtual | ||
118 | EWidgetType LLTabContainer::getWidgetType() const | ||
119 | { | ||
120 | return WIDGET_TYPE_TAB_CONTAINER; | ||
121 | } | ||
118 | 122 | ||
119 | LLTabContainerCommon::~LLTabContainerCommon() | 123 | //virtual |
124 | LLString LLTabContainer::getWidgetTag() const | ||
120 | { | 125 | { |
121 | std::for_each(mTabList.begin(), mTabList.end(), DeletePointer()); | 126 | return LL_TAB_CONTAINER_COMMON_TAG; |
122 | } | 127 | } |
123 | 128 | ||
124 | LLView* LLTabContainerCommon::getChildByName(const LLString& name, BOOL recurse) const | 129 | //virtual |
130 | void LLTabContainer::reshape(S32 width, S32 height, BOOL called_from_parent) | ||
131 | { | ||
132 | LLPanel::reshape( width, height, called_from_parent ); | ||
133 | updateMaxScrollPos(); | ||
134 | } | ||
135 | |||
136 | //virtual | ||
137 | LLView* LLTabContainer::getChildByName(const LLString& name, BOOL recurse) const | ||
125 | { | 138 | { |
126 | tuple_list_t::const_iterator itor; | 139 | tuple_list_t::const_iterator itor; |
127 | for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) | 140 | for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) |
@@ -137,7 +150,7 @@ LLView* LLTabContainerCommon::getChildByName(const LLString& name, BOOL recurse) | |||
137 | for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) | 150 | for (itor = mTabList.begin(); itor != mTabList.end(); ++itor) |
138 | { | 151 | { |
139 | LLPanel *panel = (*itor)->mTabPanel; | 152 | LLPanel *panel = (*itor)->mTabPanel; |
140 | LLView *child = panel->getChildByName(name, recurse); | 153 | LLView *child = panel->getChild<LLView>(name, recurse); |
141 | if (child) | 154 | if (child) |
142 | { | 155 | { |
143 | return child; | 156 | return child; |
@@ -147,25 +160,753 @@ LLView* LLTabContainerCommon::getChildByName(const LLString& name, BOOL recurse) | |||
147 | return LLView::getChildByName(name, recurse); | 160 | return LLView::getChildByName(name, recurse); |
148 | } | 161 | } |
149 | 162 | ||
150 | void LLTabContainerCommon::addPlaceholder(LLPanel* child, const LLString& label) | 163 | // virtual |
164 | void LLTabContainer::draw() | ||
151 | { | 165 | { |
152 | addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE); | 166 | S32 target_pixel_scroll = 0; |
167 | S32 cur_scroll_pos = mIsVertical ? 0 : getScrollPos(); | ||
168 | if (cur_scroll_pos > 0) | ||
169 | { | ||
170 | S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1); | ||
171 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
172 | { | ||
173 | if (cur_scroll_pos == 0) | ||
174 | { | ||
175 | break; | ||
176 | } | ||
177 | target_pixel_scroll += (*iter)->mButton->getRect().getWidth(); | ||
178 | cur_scroll_pos--; | ||
179 | } | ||
180 | |||
181 | // Show part of the tab to the left of what is fully visible | ||
182 | target_pixel_scroll -= TABCNTR_TAB_PARTIAL_WIDTH; | ||
183 | // clamp so that rightmost tab never leaves right side of screen | ||
184 | target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows, target_pixel_scroll); | ||
185 | } | ||
186 | |||
187 | setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f))); | ||
188 | if( getVisible() ) | ||
189 | { | ||
190 | BOOL has_scroll_arrows = (mMaxScrollPos > 0) || (mScrollPosPixels > 0); | ||
191 | if (!mIsVertical) | ||
192 | { | ||
193 | mJumpPrevArrowBtn->setVisible( has_scroll_arrows ); | ||
194 | mJumpNextArrowBtn->setVisible( has_scroll_arrows ); | ||
195 | } | ||
196 | mPrevArrowBtn->setVisible( has_scroll_arrows ); | ||
197 | mNextArrowBtn->setVisible( has_scroll_arrows ); | ||
198 | |||
199 | S32 left = 0, top = 0; | ||
200 | if (mIsVertical) | ||
201 | { | ||
202 | top = getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? TABCNTRV_ARROW_BTN_SIZE : 0); | ||
203 | top += getScrollPosPixels(); | ||
204 | } | ||
205 | else | ||
206 | { | ||
207 | // Set the leftmost position of the tab buttons. | ||
208 | left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (TABCNTR_ARROW_BTN_SIZE * 2) : TABCNTR_TAB_H_PAD); | ||
209 | left -= getScrollPosPixels(); | ||
210 | } | ||
211 | |||
212 | // Hide all the buttons | ||
213 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
214 | { | ||
215 | LLTabTuple* tuple = *iter; | ||
216 | tuple->mButton->setVisible( FALSE ); | ||
217 | } | ||
218 | |||
219 | LLPanel::draw(); | ||
220 | |||
221 | // if tabs are hidden, don't draw them and leave them in the invisible state | ||
222 | if (!getTabsHidden()) | ||
223 | { | ||
224 | // Show all the buttons | ||
225 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
226 | { | ||
227 | LLTabTuple* tuple = *iter; | ||
228 | tuple->mButton->setVisible( TRUE ); | ||
229 | } | ||
230 | |||
231 | // Draw some of the buttons... | ||
232 | LLRect clip_rect = getLocalRect(); | ||
233 | if (has_scroll_arrows) | ||
234 | { | ||
235 | // ...but clip them. | ||
236 | if (mIsVertical) | ||
237 | { | ||
238 | clip_rect.mBottom = mNextArrowBtn->getRect().mTop + 3*TABCNTRV_PAD; | ||
239 | clip_rect.mTop = mPrevArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD; | ||
240 | } | ||
241 | else | ||
242 | { | ||
243 | clip_rect.mLeft = mPrevArrowBtn->getRect().mRight; | ||
244 | clip_rect.mRight = mNextArrowBtn->getRect().mLeft; | ||
245 | } | ||
246 | } | ||
247 | LLLocalClipRect clip(clip_rect); | ||
248 | |||
249 | S32 max_scroll_visible = getTabCount() - getMaxScrollPos() + getScrollPos(); | ||
250 | S32 idx = 0; | ||
251 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
252 | { | ||
253 | LLTabTuple* tuple = *iter; | ||
254 | |||
255 | tuple->mButton->translate( left ? left - tuple->mButton->getRect().mLeft : 0, | ||
256 | top ? top - tuple->mButton->getRect().mTop : 0 ); | ||
257 | if (top) top -= BTN_HEIGHT + TABCNTRV_PAD; | ||
258 | if (left) left += tuple->mButton->getRect().getWidth(); | ||
259 | |||
260 | if (!mIsVertical) | ||
261 | { | ||
262 | if( idx < getScrollPos() ) | ||
263 | { | ||
264 | if( tuple->mButton->getFlashing() ) | ||
265 | { | ||
266 | mPrevArrowBtn->setFlashing( TRUE ); | ||
267 | } | ||
268 | } | ||
269 | else if( max_scroll_visible < idx ) | ||
270 | { | ||
271 | if( tuple->mButton->getFlashing() ) | ||
272 | { | ||
273 | mNextArrowBtn->setFlashing( TRUE ); | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | LLUI::pushMatrix(); | ||
278 | { | ||
279 | LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); | ||
280 | tuple->mButton->draw(); | ||
281 | } | ||
282 | LLUI::popMatrix(); | ||
283 | |||
284 | idx++; | ||
285 | } | ||
286 | |||
287 | |||
288 | if( mIsVertical && has_scroll_arrows ) | ||
289 | { | ||
290 | // Redraw the arrows so that they appears on top. | ||
291 | gGL.pushMatrix(); | ||
292 | gGL.translatef((F32)mPrevArrowBtn->getRect().mLeft, (F32)mPrevArrowBtn->getRect().mBottom, 0.f); | ||
293 | mPrevArrowBtn->draw(); | ||
294 | gGL.popMatrix(); | ||
295 | |||
296 | gGL.pushMatrix(); | ||
297 | gGL.translatef((F32)mNextArrowBtn->getRect().mLeft, (F32)mNextArrowBtn->getRect().mBottom, 0.f); | ||
298 | mNextArrowBtn->draw(); | ||
299 | gGL.popMatrix(); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | mPrevArrowBtn->setFlashing(FALSE); | ||
304 | mNextArrowBtn->setFlashing(FALSE); | ||
305 | } | ||
153 | } | 306 | } |
154 | 307 | ||
155 | void LLTabContainerCommon::lockTabs(S32 num_tabs) | 308 | |
309 | // virtual | ||
310 | BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) | ||
156 | { | 311 | { |
157 | // count current tabs or use supplied value and ensure no new tabs get | 312 | BOOL handled = FALSE; |
158 | // inserted between them | 313 | BOOL has_scroll_arrows = (getMaxScrollPos() > 0); |
159 | mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount(); | 314 | |
315 | if (has_scroll_arrows) | ||
316 | { | ||
317 | if (mJumpPrevArrowBtn&& mJumpPrevArrowBtn->getRect().pointInRect(x, y)) | ||
318 | { | ||
319 | S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; | ||
320 | S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; | ||
321 | handled = mJumpPrevArrowBtn->handleMouseDown(local_x, local_y, mask); | ||
322 | } | ||
323 | else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) | ||
324 | { | ||
325 | S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; | ||
326 | S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; | ||
327 | handled = mJumpNextArrowBtn->handleMouseDown(local_x, local_y, mask); | ||
328 | } | ||
329 | else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) | ||
330 | { | ||
331 | S32 local_x = x - mPrevArrowBtn->getRect().mLeft; | ||
332 | S32 local_y = y - mPrevArrowBtn->getRect().mBottom; | ||
333 | handled = mPrevArrowBtn->handleMouseDown(local_x, local_y, mask); | ||
334 | } | ||
335 | else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) | ||
336 | { | ||
337 | S32 local_x = x - mNextArrowBtn->getRect().mLeft; | ||
338 | S32 local_y = y - mNextArrowBtn->getRect().mBottom; | ||
339 | handled = mNextArrowBtn->handleMouseDown(local_x, local_y, mask); | ||
340 | } | ||
341 | } | ||
342 | if (!handled) | ||
343 | { | ||
344 | handled = LLPanel::handleMouseDown( x, y, mask ); | ||
345 | } | ||
346 | |||
347 | S32 tab_count = getTabCount(); | ||
348 | if (tab_count > 0) | ||
349 | { | ||
350 | LLTabTuple* firsttuple = getTab(0); | ||
351 | LLRect tab_rect; | ||
352 | if (mIsVertical) | ||
353 | { | ||
354 | tab_rect = LLRect(firsttuple->mButton->getRect().mLeft, | ||
355 | has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD : mPrevArrowBtn->getRect().mTop, | ||
356 | firsttuple->mButton->getRect().mRight, | ||
357 | has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD : mNextArrowBtn->getRect().mBottom ); | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | tab_rect = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft, | ||
362 | firsttuple->mButton->getRect().mTop, | ||
363 | has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, | ||
364 | firsttuple->mButton->getRect().mBottom ); | ||
365 | } | ||
366 | if( tab_rect.pointInRect( x, y ) ) | ||
367 | { | ||
368 | S32 index = getCurrentPanelIndex(); | ||
369 | index = llclamp(index, 0, tab_count-1); | ||
370 | LLButton* tab_button = getTab(index)->mButton; | ||
371 | gFocusMgr.setMouseCapture(this); | ||
372 | gFocusMgr.setKeyboardFocus(tab_button); | ||
373 | } | ||
374 | } | ||
375 | return handled; | ||
376 | } | ||
377 | |||
378 | // virtual | ||
379 | BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask ) | ||
380 | { | ||
381 | BOOL handled = FALSE; | ||
382 | BOOL has_scroll_arrows = (getMaxScrollPos() > 0); | ||
383 | |||
384 | if (has_scroll_arrows) | ||
385 | { | ||
386 | if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) | ||
387 | { | ||
388 | S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; | ||
389 | S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; | ||
390 | handled = mJumpPrevArrowBtn->handleHover(local_x, local_y, mask); | ||
391 | } | ||
392 | else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) | ||
393 | { | ||
394 | S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; | ||
395 | S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; | ||
396 | handled = mJumpNextArrowBtn->handleHover(local_x, local_y, mask); | ||
397 | } | ||
398 | else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) | ||
399 | { | ||
400 | S32 local_x = x - mPrevArrowBtn->getRect().mLeft; | ||
401 | S32 local_y = y - mPrevArrowBtn->getRect().mBottom; | ||
402 | handled = mPrevArrowBtn->handleHover(local_x, local_y, mask); | ||
403 | } | ||
404 | else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) | ||
405 | { | ||
406 | S32 local_x = x - mNextArrowBtn->getRect().mLeft; | ||
407 | S32 local_y = y - mNextArrowBtn->getRect().mBottom; | ||
408 | handled = mNextArrowBtn->handleHover(local_x, local_y, mask); | ||
409 | } | ||
410 | } | ||
411 | if (!handled) | ||
412 | { | ||
413 | handled = LLPanel::handleHover(x, y, mask); | ||
414 | } | ||
415 | |||
416 | commitHoveredButton(x, y); | ||
417 | return handled; | ||
160 | } | 418 | } |
161 | 419 | ||
162 | void LLTabContainerCommon::unlockTabs() | 420 | // virtual |
421 | BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) | ||
163 | { | 422 | { |
164 | mLockedTabCount = 0; | 423 | BOOL handled = FALSE; |
424 | BOOL has_scroll_arrows = (getMaxScrollPos() > 0); | ||
425 | |||
426 | if (has_scroll_arrows) | ||
427 | { | ||
428 | if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) | ||
429 | { | ||
430 | S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; | ||
431 | S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; | ||
432 | handled = mJumpPrevArrowBtn->handleMouseUp(local_x, local_y, mask); | ||
433 | } | ||
434 | else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) | ||
435 | { | ||
436 | S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; | ||
437 | S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; | ||
438 | handled = mJumpNextArrowBtn->handleMouseUp(local_x, local_y, mask); | ||
439 | } | ||
440 | else if (mPrevArrowBtn && mPrevArrowBtn->getRect().pointInRect(x, y)) | ||
441 | { | ||
442 | S32 local_x = x - mPrevArrowBtn->getRect().mLeft; | ||
443 | S32 local_y = y - mPrevArrowBtn->getRect().mBottom; | ||
444 | handled = mPrevArrowBtn->handleMouseUp(local_x, local_y, mask); | ||
445 | } | ||
446 | else if (mNextArrowBtn && mNextArrowBtn->getRect().pointInRect(x, y)) | ||
447 | { | ||
448 | S32 local_x = x - mNextArrowBtn->getRect().mLeft; | ||
449 | S32 local_y = y - mNextArrowBtn->getRect().mBottom; | ||
450 | handled = mNextArrowBtn->handleMouseUp(local_x, local_y, mask); | ||
451 | } | ||
452 | } | ||
453 | if (!handled) | ||
454 | { | ||
455 | handled = LLPanel::handleMouseUp( x, y, mask ); | ||
456 | } | ||
457 | |||
458 | commitHoveredButton(x, y); | ||
459 | LLPanel* cur_panel = getCurrentPanel(); | ||
460 | if (hasMouseCapture()) | ||
461 | { | ||
462 | if (cur_panel) | ||
463 | { | ||
464 | if (!cur_panel->focusFirstItem(FALSE)) | ||
465 | { | ||
466 | // if nothing in the panel gets focus, make sure the new tab does | ||
467 | // otherwise the last tab might keep focus | ||
468 | getTab(getCurrentPanelIndex())->mButton->setFocus(TRUE); | ||
469 | } | ||
470 | } | ||
471 | gFocusMgr.setMouseCapture(NULL); | ||
472 | } | ||
473 | return handled; | ||
474 | } | ||
475 | |||
476 | // virtual | ||
477 | BOOL LLTabContainer::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect ) | ||
478 | { | ||
479 | BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect ); | ||
480 | if (!handled && getTabCount() > 0) | ||
481 | { | ||
482 | LLTabTuple* firsttuple = getTab(0); | ||
483 | |||
484 | BOOL has_scroll_arrows = (getMaxScrollPos() > 0); | ||
485 | LLRect clip; | ||
486 | if (mIsVertical) | ||
487 | { | ||
488 | clip = LLRect(firsttuple->mButton->getRect().mLeft, | ||
489 | has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD : mPrevArrowBtn->getRect().mTop, | ||
490 | firsttuple->mButton->getRect().mRight, | ||
491 | has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD : mNextArrowBtn->getRect().mBottom ); | ||
492 | } | ||
493 | else | ||
494 | { | ||
495 | clip = LLRect(has_scroll_arrows ? mPrevArrowBtn->getRect().mRight : mJumpPrevArrowBtn->getRect().mLeft, | ||
496 | firsttuple->mButton->getRect().mTop, | ||
497 | has_scroll_arrows ? mNextArrowBtn->getRect().mLeft : mJumpNextArrowBtn->getRect().mRight, | ||
498 | firsttuple->mButton->getRect().mBottom ); | ||
499 | } | ||
500 | |||
501 | if( clip.pointInRect( x, y ) ) | ||
502 | { | ||
503 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
504 | { | ||
505 | LLTabTuple* tuple = *iter; | ||
506 | tuple->mButton->setVisible( TRUE ); | ||
507 | S32 local_x = x - tuple->mButton->getRect().mLeft; | ||
508 | S32 local_y = y - tuple->mButton->getRect().mBottom; | ||
509 | handled = tuple->mButton->handleToolTip( local_x, local_y, msg, sticky_rect ); | ||
510 | if( handled ) | ||
511 | { | ||
512 | break; | ||
513 | } | ||
514 | } | ||
515 | } | ||
516 | |||
517 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
518 | { | ||
519 | LLTabTuple* tuple = *iter; | ||
520 | tuple->mButton->setVisible( FALSE ); | ||
521 | } | ||
522 | } | ||
523 | return handled; | ||
524 | } | ||
525 | |||
526 | // virtual | ||
527 | BOOL LLTabContainer::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent) | ||
528 | { | ||
529 | if (!getEnabled()) return FALSE; | ||
530 | |||
531 | if (!gFocusMgr.childHasKeyboardFocus(this)) return FALSE; | ||
532 | |||
533 | BOOL handled = FALSE; | ||
534 | if (key == KEY_LEFT && mask == MASK_ALT) | ||
535 | { | ||
536 | selectPrevTab(); | ||
537 | handled = TRUE; | ||
538 | } | ||
539 | else if (key == KEY_RIGHT && mask == MASK_ALT) | ||
540 | { | ||
541 | selectNextTab(); | ||
542 | handled = TRUE; | ||
543 | } | ||
544 | |||
545 | if (handled) | ||
546 | { | ||
547 | if (getCurrentPanel()) | ||
548 | { | ||
549 | getCurrentPanel()->setFocus(TRUE); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | if (!gFocusMgr.childHasKeyboardFocus(getCurrentPanel())) | ||
554 | { | ||
555 | // if child has focus, but not the current panel, focus is on a button | ||
556 | if (mIsVertical) | ||
557 | { | ||
558 | switch(key) | ||
559 | { | ||
560 | case KEY_UP: | ||
561 | selectPrevTab(); | ||
562 | handled = TRUE; | ||
563 | break; | ||
564 | case KEY_DOWN: | ||
565 | selectNextTab(); | ||
566 | handled = TRUE; | ||
567 | break; | ||
568 | case KEY_LEFT: | ||
569 | handled = TRUE; | ||
570 | break; | ||
571 | case KEY_RIGHT: | ||
572 | if (getTabPosition() == LEFT && getCurrentPanel()) | ||
573 | { | ||
574 | getCurrentPanel()->setFocus(TRUE); | ||
575 | } | ||
576 | handled = TRUE; | ||
577 | break; | ||
578 | default: | ||
579 | break; | ||
580 | } | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | switch(key) | ||
585 | { | ||
586 | case KEY_UP: | ||
587 | if (getTabPosition() == BOTTOM && getCurrentPanel()) | ||
588 | { | ||
589 | getCurrentPanel()->setFocus(TRUE); | ||
590 | } | ||
591 | handled = TRUE; | ||
592 | break; | ||
593 | case KEY_DOWN: | ||
594 | if (getTabPosition() == TOP && getCurrentPanel()) | ||
595 | { | ||
596 | getCurrentPanel()->setFocus(TRUE); | ||
597 | } | ||
598 | handled = TRUE; | ||
599 | break; | ||
600 | case KEY_LEFT: | ||
601 | selectPrevTab(); | ||
602 | handled = TRUE; | ||
603 | break; | ||
604 | case KEY_RIGHT: | ||
605 | selectNextTab(); | ||
606 | handled = TRUE; | ||
607 | break; | ||
608 | default: | ||
609 | break; | ||
610 | } | ||
611 | } | ||
612 | } | ||
613 | return handled; | ||
614 | } | ||
615 | |||
616 | // virtual | ||
617 | LLXMLNodePtr LLTabContainer::getXML(bool save_children) const | ||
618 | { | ||
619 | LLXMLNodePtr node = LLPanel::getXML(); | ||
620 | node->createChild("tab_position", TRUE)->setStringValue((getTabPosition() == TOP ? "top" : "bottom")); | ||
621 | return node; | ||
622 | } | ||
623 | |||
624 | // virtual | ||
625 | BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType type, void* cargo_data, EAcceptance *accept, LLString &tooltip) | ||
626 | { | ||
627 | BOOL has_scroll_arrows = (getMaxScrollPos() > 0); | ||
628 | |||
629 | if( mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME ) | ||
630 | { | ||
631 | if (has_scroll_arrows) | ||
632 | { | ||
633 | if (mJumpPrevArrowBtn->getRect().pointInRect(x, y)) | ||
634 | { | ||
635 | S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; | ||
636 | S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; | ||
637 | mJumpPrevArrowBtn->handleHover(local_x, local_y, mask); | ||
638 | } | ||
639 | if (mJumpNextArrowBtn->getRect().pointInRect(x, y)) | ||
640 | { | ||
641 | S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; | ||
642 | S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; | ||
643 | mJumpNextArrowBtn->handleHover(local_x, local_y, mask); | ||
644 | } | ||
645 | if (mPrevArrowBtn->getRect().pointInRect(x, y)) | ||
646 | { | ||
647 | S32 local_x = x - mPrevArrowBtn->getRect().mLeft; | ||
648 | S32 local_y = y - mPrevArrowBtn->getRect().mBottom; | ||
649 | mPrevArrowBtn->handleHover(local_x, local_y, mask); | ||
650 | } | ||
651 | else if (mNextArrowBtn->getRect().pointInRect(x, y)) | ||
652 | { | ||
653 | S32 local_x = x - mNextArrowBtn->getRect().mLeft; | ||
654 | S32 local_y = y - mNextArrowBtn->getRect().mBottom; | ||
655 | mNextArrowBtn->handleHover(local_x, local_y, mask); | ||
656 | } | ||
657 | } | ||
658 | |||
659 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
660 | { | ||
661 | LLTabTuple* tuple = *iter; | ||
662 | tuple->mButton->setVisible( TRUE ); | ||
663 | S32 local_x = x - tuple->mButton->getRect().mLeft; | ||
664 | S32 local_y = y - tuple->mButton->getRect().mBottom; | ||
665 | if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) | ||
666 | { | ||
667 | tuple->mButton->onCommit(); | ||
668 | mDragAndDropDelayTimer.stop(); | ||
669 | } | ||
670 | } | ||
671 | } | ||
672 | |||
673 | return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); | ||
165 | } | 674 | } |
166 | 675 | ||
167 | void LLTabContainerCommon::removeTabPanel(LLPanel* child) | 676 | void LLTabContainer::addTabPanel(LLPanel* child, |
677 | const LLString& label, | ||
678 | BOOL select, | ||
679 | void (*on_tab_clicked)(void*, bool), | ||
680 | void* userdata, | ||
681 | S32 indent, | ||
682 | BOOL placeholder, | ||
683 | eInsertionPoint insertion_point) | ||
168 | { | 684 | { |
685 | if (child->getParent() == this) | ||
686 | { | ||
687 | // already a child of mine | ||
688 | return; | ||
689 | } | ||
690 | const LLFontGL* font = gResMgr->getRes( mIsVertical ? LLFONT_SANSSERIF : LLFONT_SANSSERIF_SMALL ); | ||
691 | |||
692 | // Store the original label for possible xml export. | ||
693 | child->setLabel(label); | ||
694 | LLString trimmed_label = label; | ||
695 | LLString::trim(trimmed_label); | ||
696 | |||
697 | S32 button_width = mMinTabWidth; | ||
698 | if (!mIsVertical) | ||
699 | { | ||
700 | button_width = llclamp(font->getWidth(trimmed_label) + TAB_PADDING, mMinTabWidth, mMaxTabWidth); | ||
701 | } | ||
702 | |||
703 | // Tab panel | ||
704 | S32 tab_panel_top; | ||
705 | S32 tab_panel_bottom; | ||
706 | if( getTabPosition() == LLTabContainer::TOP ) | ||
707 | { | ||
708 | S32 tab_height = mIsVertical ? BTN_HEIGHT : TABCNTR_TAB_HEIGHT; | ||
709 | tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP); | ||
710 | tab_panel_bottom = LLPANEL_BORDER_WIDTH; | ||
711 | } | ||
712 | else | ||
713 | { | ||
714 | tab_panel_top = getRect().getHeight() - getTopBorderHeight(); | ||
715 | tab_panel_bottom = (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP); // Run to the edge, covering up the border | ||
716 | } | ||
717 | |||
718 | LLRect tab_panel_rect; | ||
719 | if (mIsVertical) | ||
720 | { | ||
721 | tab_panel_rect = LLRect(mMinTabWidth + (LLPANEL_BORDER_WIDTH * 2) + TABCNTRV_PAD, | ||
722 | getRect().getHeight() - LLPANEL_BORDER_WIDTH, | ||
723 | getRect().getWidth() - LLPANEL_BORDER_WIDTH, | ||
724 | LLPANEL_BORDER_WIDTH); | ||
725 | } | ||
726 | else | ||
727 | { | ||
728 | tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH, | ||
729 | tab_panel_top, | ||
730 | getRect().getWidth()-LLPANEL_BORDER_WIDTH, | ||
731 | tab_panel_bottom ); | ||
732 | } | ||
733 | child->setFollowsAll(); | ||
734 | child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom); | ||
735 | child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE ); | ||
736 | child->setBackgroundVisible( FALSE ); // No need to overdraw | ||
737 | // add this child later | ||
738 | |||
739 | child->setVisible( FALSE ); // Will be made visible when selected | ||
740 | |||
741 | mTotalTabWidth += button_width; | ||
742 | |||
743 | // Tab button | ||
744 | LLRect btn_rect; // Note: btn_rect.mLeft is just a dummy. Will be updated in draw(). | ||
745 | LLString tab_img; | ||
746 | LLString tab_selected_img; | ||
747 | S32 tab_fudge = 1; // To make new tab art look better, nudge buttons up 1 pel | ||
748 | |||
749 | if (mIsVertical) | ||
750 | { | ||
751 | btn_rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor | ||
752 | (getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * getTabCount()), | ||
753 | mMinTabWidth, | ||
754 | BTN_HEIGHT); | ||
755 | } | ||
756 | else if( getTabPosition() == LLTabContainer::TOP ) | ||
757 | { | ||
758 | btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, TABCNTR_TAB_HEIGHT ); | ||
759 | tab_img = "tab_top_blue.tga"; | ||
760 | tab_selected_img = "tab_top_selected_blue.tga"; | ||
761 | } | ||
762 | else | ||
763 | { | ||
764 | btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, TABCNTR_TAB_HEIGHT ); | ||
765 | tab_img = "tab_bottom_blue.tga"; | ||
766 | tab_selected_img = "tab_bottom_selected_blue.tga"; | ||
767 | } | ||
768 | |||
769 | LLTextBox* textbox = NULL; | ||
770 | LLButton* btn = NULL; | ||
771 | |||
772 | if (placeholder) | ||
773 | { | ||
774 | btn_rect.translate(0, -LLBUTTON_V_PAD-2); | ||
775 | textbox = new LLTextBox(trimmed_label, btn_rect, trimmed_label, font); | ||
776 | |||
777 | btn = new LLButton("", LLRect(0,0,0,0)); | ||
778 | } | ||
779 | else | ||
780 | { | ||
781 | if (mIsVertical) | ||
782 | { | ||
783 | btn = new LLButton("vert tab button", | ||
784 | btn_rect, | ||
785 | "", | ||
786 | "", | ||
787 | "", | ||
788 | &LLTabContainer::onTabBtn, NULL, | ||
789 | font, | ||
790 | trimmed_label, trimmed_label); | ||
791 | btn->setImages("tab_left.tga", "tab_left_selected.tga"); | ||
792 | btn->setScaleImage(TRUE); | ||
793 | btn->setHAlign(LLFontGL::LEFT); | ||
794 | btn->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT); | ||
795 | btn->setTabStop(FALSE); | ||
796 | if (indent) | ||
797 | { | ||
798 | btn->setLeftHPad(indent); | ||
799 | } | ||
800 | } | ||
801 | else | ||
802 | { | ||
803 | LLString tooltip = trimmed_label; | ||
804 | tooltip += "\nAlt-Left arrow for previous tab"; | ||
805 | tooltip += "\nAlt-Right arrow for next tab"; | ||
806 | |||
807 | btn = new LLButton(LLString(child->getName()) + " tab", | ||
808 | btn_rect, | ||
809 | "", "", "", | ||
810 | &LLTabContainer::onTabBtn, NULL, // set userdata below | ||
811 | font, | ||
812 | trimmed_label, trimmed_label ); | ||
813 | btn->setVisible( FALSE ); | ||
814 | btn->setToolTip( tooltip ); | ||
815 | btn->setScaleImage(TRUE); | ||
816 | btn->setImages(tab_img, tab_selected_img); | ||
817 | |||
818 | // Try to squeeze in a bit more text | ||
819 | btn->setLeftHPad( 4 ); | ||
820 | btn->setRightHPad( 2 ); | ||
821 | btn->setHAlign(LLFontGL::LEFT); | ||
822 | btn->setTabStop(FALSE); | ||
823 | if (indent) | ||
824 | { | ||
825 | btn->setLeftHPad(indent); | ||
826 | } | ||
827 | |||
828 | if( getTabPosition() == TOP ) | ||
829 | { | ||
830 | btn->setFollowsTop(); | ||
831 | } | ||
832 | else | ||
833 | { | ||
834 | btn->setFollowsBottom(); | ||
835 | } | ||
836 | } | ||
837 | } | ||
838 | |||
839 | LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata, textbox ); | ||
840 | insertTuple( tuple, insertion_point ); | ||
841 | |||
842 | if (textbox) | ||
843 | { | ||
844 | textbox->setSaveToXML(false); | ||
845 | addChild( textbox, 0 ); | ||
846 | } | ||
847 | if (btn) | ||
848 | { | ||
849 | btn->setSaveToXML(false); | ||
850 | btn->setCallbackUserData( tuple ); | ||
851 | addChild( btn, 0 ); | ||
852 | } | ||
853 | if (child) | ||
854 | { | ||
855 | addChild(child, 1); | ||
856 | } | ||
857 | |||
858 | if( select ) | ||
859 | { | ||
860 | selectLastTab(); | ||
861 | } | ||
862 | |||
863 | updateMaxScrollPos(); | ||
864 | } | ||
865 | |||
866 | void LLTabContainer::addPlaceholder(LLPanel* child, const LLString& label) | ||
867 | { | ||
868 | addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE); | ||
869 | } | ||
870 | |||
871 | void LLTabContainer::removeTabPanel(LLPanel* child) | ||
872 | { | ||
873 | if (mIsVertical) | ||
874 | { | ||
875 | // Fix-up button sizes | ||
876 | S32 tab_count = 0; | ||
877 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
878 | { | ||
879 | LLTabTuple* tuple = *iter; | ||
880 | LLRect rect; | ||
881 | rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor | ||
882 | (getRect().getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * (tab_count)), | ||
883 | mMinTabWidth, | ||
884 | BTN_HEIGHT); | ||
885 | if (tuple->mPlaceholderText) | ||
886 | { | ||
887 | tuple->mPlaceholderText->setRect(rect); | ||
888 | } | ||
889 | else | ||
890 | { | ||
891 | tuple->mButton->setRect(rect); | ||
892 | } | ||
893 | tab_count++; | ||
894 | } | ||
895 | } | ||
896 | else | ||
897 | { | ||
898 | // Adjust the total tab width. | ||
899 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
900 | { | ||
901 | LLTabTuple* tuple = *iter; | ||
902 | if( tuple->mTabPanel == child ) | ||
903 | { | ||
904 | mTotalTabWidth -= tuple->mButton->getRect().getWidth(); | ||
905 | break; | ||
906 | } | ||
907 | } | ||
908 | } | ||
909 | |||
169 | BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this); | 910 | BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this); |
170 | 911 | ||
171 | // If the tab being deleted is the selected one, select a different tab. | 912 | // If the tab being deleted is the selected one, select a different tab. |
@@ -207,7 +948,27 @@ void LLTabContainerCommon::removeTabPanel(LLPanel* child) | |||
207 | updateMaxScrollPos(); | 948 | updateMaxScrollPos(); |
208 | } | 949 | } |
209 | 950 | ||
210 | void LLTabContainerCommon::deleteAllTabs() | 951 | void LLTabContainer::lockTabs(S32 num_tabs) |
952 | { | ||
953 | // count current tabs or use supplied value and ensure no new tabs get | ||
954 | // inserted between them | ||
955 | mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount(); | ||
956 | } | ||
957 | |||
958 | void LLTabContainer::unlockTabs() | ||
959 | { | ||
960 | mLockedTabCount = 0; | ||
961 | } | ||
962 | |||
963 | void LLTabContainer::enableTabButton(S32 which, BOOL enable) | ||
964 | { | ||
965 | if (which >= 0 && which < (S32)mTabList.size()) | ||
966 | { | ||
967 | mTabList[which]->mButton->setEnabled(enable); | ||
968 | } | ||
969 | } | ||
970 | |||
971 | void LLTabContainer::deleteAllTabs() | ||
211 | { | 972 | { |
212 | // Remove all the tab buttons and delete them. Also, unlink all the child panels. | 973 | // Remove all the tab buttons and delete them. Also, unlink all the child panels. |
213 | for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | 974 | for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) |
@@ -229,56 +990,26 @@ void LLTabContainerCommon::deleteAllTabs() | |||
229 | mCurrentTabIdx = -1; | 990 | mCurrentTabIdx = -1; |
230 | } | 991 | } |
231 | 992 | ||
232 | 993 | LLPanel* LLTabContainer::getCurrentPanel() | |
233 | LLPanel* LLTabContainerCommon::getCurrentPanel() | ||
234 | { | 994 | { |
235 | if (mCurrentTabIdx < 0 || mCurrentTabIdx >= (S32) mTabList.size()) return NULL; | 995 | if (mCurrentTabIdx >= 0 && mCurrentTabIdx < (S32) mTabList.size()) |
236 | |||
237 | return mTabList[mCurrentTabIdx]->mTabPanel; | ||
238 | } | ||
239 | |||
240 | LLTabContainerCommon::LLTabTuple* LLTabContainerCommon::getTabByPanel(LLPanel* child) | ||
241 | { | ||
242 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
243 | { | 996 | { |
244 | LLTabTuple* tuple = *iter; | 997 | return mTabList[mCurrentTabIdx]->mTabPanel; |
245 | if( tuple->mTabPanel == child ) | ||
246 | { | ||
247 | return tuple; | ||
248 | } | ||
249 | } | 998 | } |
250 | return NULL; | 999 | return NULL; |
251 | } | 1000 | } |
252 | 1001 | ||
253 | void LLTabContainerCommon::setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*, bool)) | 1002 | S32 LLTabContainer::getCurrentPanelIndex() |
254 | { | ||
255 | LLTabTuple* tuplep = getTabByPanel(tab); | ||
256 | if (tuplep) | ||
257 | { | ||
258 | tuplep->mOnChangeCallback = on_tab_clicked; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | void LLTabContainerCommon::setTabUserData(LLPanel* tab, void* userdata) | ||
263 | { | ||
264 | LLTabTuple* tuplep = getTabByPanel(tab); | ||
265 | if (tuplep) | ||
266 | { | ||
267 | tuplep->mUserData = userdata; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | S32 LLTabContainerCommon::getCurrentPanelIndex() | ||
272 | { | 1003 | { |
273 | return mCurrentTabIdx; | 1004 | return mCurrentTabIdx; |
274 | } | 1005 | } |
275 | 1006 | ||
276 | S32 LLTabContainerCommon::getTabCount() | 1007 | S32 LLTabContainer::getTabCount() |
277 | { | 1008 | { |
278 | return mTabList.size(); | 1009 | return mTabList.size(); |
279 | } | 1010 | } |
280 | 1011 | ||
281 | LLPanel* LLTabContainerCommon::getPanelByIndex(S32 index) | 1012 | LLPanel* LLTabContainer::getPanelByIndex(S32 index) |
282 | { | 1013 | { |
283 | if (index >= 0 && index < (S32)mTabList.size()) | 1014 | if (index >= 0 && index < (S32)mTabList.size()) |
284 | { | 1015 | { |
@@ -287,7 +1018,7 @@ LLPanel* LLTabContainerCommon::getPanelByIndex(S32 index) | |||
287 | return NULL; | 1018 | return NULL; |
288 | } | 1019 | } |
289 | 1020 | ||
290 | S32 LLTabContainerCommon::getIndexForPanel(LLPanel* panel) | 1021 | S32 LLTabContainer::getIndexForPanel(LLPanel* panel) |
291 | { | 1022 | { |
292 | for (S32 index = 0; index < (S32)mTabList.size(); index++) | 1023 | for (S32 index = 0; index < (S32)mTabList.size(); index++) |
293 | { | 1024 | { |
@@ -299,7 +1030,7 @@ S32 LLTabContainerCommon::getIndexForPanel(LLPanel* panel) | |||
299 | return -1; | 1030 | return -1; |
300 | } | 1031 | } |
301 | 1032 | ||
302 | S32 LLTabContainerCommon::getPanelIndexByTitle(const LLString& title) | 1033 | S32 LLTabContainer::getPanelIndexByTitle(const LLString& title) |
303 | { | 1034 | { |
304 | for (S32 index = 0 ; index < (S32)mTabList.size(); index++) | 1035 | for (S32 index = 0 ; index < (S32)mTabList.size(); index++) |
305 | { | 1036 | { |
@@ -311,7 +1042,7 @@ S32 LLTabContainerCommon::getPanelIndexByTitle(const LLString& title) | |||
311 | return -1; | 1042 | return -1; |
312 | } | 1043 | } |
313 | 1044 | ||
314 | LLPanel *LLTabContainerCommon::getPanelByName(const LLString& name) | 1045 | LLPanel *LLTabContainer::getPanelByName(const LLString& name) |
315 | { | 1046 | { |
316 | for (S32 index = 0 ; index < (S32)mTabList.size(); index++) | 1047 | for (S32 index = 0 ; index < (S32)mTabList.size(); index++) |
317 | { | 1048 | { |
@@ -324,34 +1055,71 @@ LLPanel *LLTabContainerCommon::getPanelByName(const LLString& name) | |||
324 | return NULL; | 1055 | return NULL; |
325 | } | 1056 | } |
326 | 1057 | ||
1058 | // Change the name of the button for the current tab. | ||
1059 | void LLTabContainer::setCurrentTabName(const LLString& name) | ||
1060 | { | ||
1061 | // Might not have a tab selected | ||
1062 | if (mCurrentTabIdx < 0) return; | ||
1063 | |||
1064 | mTabList[mCurrentTabIdx]->mButton->setLabelSelected(name); | ||
1065 | mTabList[mCurrentTabIdx]->mButton->setLabelUnselected(name); | ||
1066 | } | ||
327 | 1067 | ||
328 | void LLTabContainerCommon::scrollNext() | 1068 | void LLTabContainer::selectFirstTab() |
329 | { | 1069 | { |
330 | // No wrap | 1070 | selectTab( 0 ); |
331 | if( mScrollPos < mMaxScrollPos ) | ||
332 | { | ||
333 | mScrollPos++; | ||
334 | } | ||
335 | } | 1071 | } |
336 | 1072 | ||
337 | void LLTabContainerCommon::scrollPrev() | 1073 | |
1074 | void LLTabContainer::selectLastTab() | ||
338 | { | 1075 | { |
339 | // No wrap | 1076 | selectTab( mTabList.size()-1 ); |
340 | if( mScrollPos > 0 ) | 1077 | } |
1078 | |||
1079 | void LLTabContainer::selectNextTab() | ||
1080 | { | ||
1081 | BOOL tab_has_focus = FALSE; | ||
1082 | if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus()) | ||
1083 | { | ||
1084 | tab_has_focus = TRUE; | ||
1085 | } | ||
1086 | S32 idx = mCurrentTabIdx+1; | ||
1087 | if (idx >= (S32)mTabList.size()) | ||
1088 | idx = 0; | ||
1089 | while (!selectTab(idx) && idx != mCurrentTabIdx) | ||
341 | { | 1090 | { |
342 | mScrollPos--; | 1091 | idx = (idx + 1 ) % (S32)mTabList.size(); |
1092 | } | ||
1093 | |||
1094 | if (tab_has_focus) | ||
1095 | { | ||
1096 | mTabList[idx]->mButton->setFocus(TRUE); | ||
343 | } | 1097 | } |
344 | } | 1098 | } |
345 | 1099 | ||
346 | void LLTabContainerCommon::enableTabButton(S32 which, BOOL enable) | 1100 | void LLTabContainer::selectPrevTab() |
347 | { | 1101 | { |
348 | if (which >= 0 && which < (S32)mTabList.size()) | 1102 | BOOL tab_has_focus = FALSE; |
1103 | if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus()) | ||
349 | { | 1104 | { |
350 | mTabList[which]->mButton->setEnabled(enable); | 1105 | tab_has_focus = TRUE; |
351 | } | 1106 | } |
352 | } | 1107 | S32 idx = mCurrentTabIdx-1; |
1108 | if (idx < 0) | ||
1109 | idx = mTabList.size()-1; | ||
1110 | while (!selectTab(idx) && idx != mCurrentTabIdx) | ||
1111 | { | ||
1112 | idx = idx - 1; | ||
1113 | if (idx < 0) | ||
1114 | idx = mTabList.size()-1; | ||
1115 | } | ||
1116 | if (tab_has_focus) | ||
1117 | { | ||
1118 | mTabList[idx]->mButton->setFocus(TRUE); | ||
1119 | } | ||
1120 | } | ||
353 | 1121 | ||
354 | BOOL LLTabContainerCommon::selectTabPanel(LLPanel* child) | 1122 | BOOL LLTabContainer::selectTabPanel(LLPanel* child) |
355 | { | 1123 | { |
356 | S32 idx = 0; | 1124 | S32 idx = 0; |
357 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | 1125 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) |
@@ -366,12 +1134,108 @@ BOOL LLTabContainerCommon::selectTabPanel(LLPanel* child) | |||
366 | return FALSE; | 1134 | return FALSE; |
367 | } | 1135 | } |
368 | 1136 | ||
369 | BOOL LLTabContainerCommon::selectTabByName(const LLString& name) | 1137 | BOOL LLTabContainer::selectTab(S32 which) |
1138 | { | ||
1139 | if (which >= getTabCount()) return FALSE; | ||
1140 | if (which < 0) return FALSE; | ||
1141 | |||
1142 | //if( gFocusMgr.childHasKeyboardFocus( this ) ) | ||
1143 | //{ | ||
1144 | // gFocusMgr.setKeyboardFocus( NULL ); | ||
1145 | //} | ||
1146 | |||
1147 | LLTabTuple* selected_tuple = getTab(which); | ||
1148 | if (!selected_tuple) | ||
1149 | { | ||
1150 | return FALSE; | ||
1151 | } | ||
1152 | |||
1153 | BOOL is_visible = FALSE; | ||
1154 | if (getTab(which)->mButton->getEnabled()) | ||
1155 | { | ||
1156 | setCurrentPanelIndex(which); | ||
1157 | |||
1158 | S32 i = 0; | ||
1159 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
1160 | { | ||
1161 | LLTabTuple* tuple = *iter; | ||
1162 | BOOL is_selected = ( tuple == selected_tuple ); | ||
1163 | tuple->mTabPanel->setVisible( is_selected ); | ||
1164 | // tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. | ||
1165 | tuple->mButton->setToggleState( is_selected ); | ||
1166 | // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs | ||
1167 | tuple->mButton->setTabStop( is_selected ); | ||
1168 | |||
1169 | if( is_selected && (mIsVertical || (getMaxScrollPos() > 0))) | ||
1170 | { | ||
1171 | // Make sure selected tab is within scroll region | ||
1172 | if (mIsVertical) | ||
1173 | { | ||
1174 | S32 num_visible = getTabCount() - getMaxScrollPos(); | ||
1175 | if( i >= getScrollPos() && i <= getScrollPos() + num_visible) | ||
1176 | { | ||
1177 | setCurrentPanelIndex(which); | ||
1178 | is_visible = TRUE; | ||
1179 | } | ||
1180 | else | ||
1181 | { | ||
1182 | is_visible = FALSE; | ||
1183 | } | ||
1184 | } | ||
1185 | else | ||
1186 | { | ||
1187 | if( i < getScrollPos() ) | ||
1188 | { | ||
1189 | setScrollPos(i); | ||
1190 | } | ||
1191 | else | ||
1192 | { | ||
1193 | S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1); | ||
1194 | S32 running_tab_width = tuple->mButton->getRect().getWidth(); | ||
1195 | S32 j = i - 1; | ||
1196 | S32 min_scroll_pos = i; | ||
1197 | if (running_tab_width < available_width_with_arrows) | ||
1198 | { | ||
1199 | while (j >= 0) | ||
1200 | { | ||
1201 | LLTabTuple* other_tuple = getTab(j); | ||
1202 | running_tab_width += other_tuple->mButton->getRect().getWidth(); | ||
1203 | if (running_tab_width > available_width_with_arrows) | ||
1204 | { | ||
1205 | break; | ||
1206 | } | ||
1207 | j--; | ||
1208 | } | ||
1209 | min_scroll_pos = j + 1; | ||
1210 | } | ||
1211 | setScrollPos(llclamp(getScrollPos(), min_scroll_pos, i)); | ||
1212 | setScrollPos(llmin(getScrollPos(), getMaxScrollPos())); | ||
1213 | } | ||
1214 | is_visible = TRUE; | ||
1215 | } | ||
1216 | } | ||
1217 | i++; | ||
1218 | } | ||
1219 | if( selected_tuple->mOnChangeCallback ) | ||
1220 | { | ||
1221 | selected_tuple->mOnChangeCallback( selected_tuple->mUserData, false ); | ||
1222 | } | ||
1223 | } | ||
1224 | if (mIsVertical && getCurrentPanelIndex() >= 0) | ||
1225 | { | ||
1226 | LLTabTuple* tuple = getTab(getCurrentPanelIndex()); | ||
1227 | tuple->mTabPanel->setVisible( TRUE ); | ||
1228 | tuple->mButton->setToggleState( TRUE ); | ||
1229 | } | ||
1230 | return is_visible; | ||
1231 | } | ||
1232 | |||
1233 | BOOL LLTabContainer::selectTabByName(const LLString& name) | ||
370 | { | 1234 | { |
371 | LLPanel* panel = getPanelByName(name); | 1235 | LLPanel* panel = getPanelByName(name); |
372 | if (!panel) | 1236 | if (!panel) |
373 | { | 1237 | { |
374 | llwarns << "LLTabContainerCommon::selectTabByName(" | 1238 | llwarns << "LLTabContainer::selectTabByName(" |
375 | << name << ") failed" << llendl; | 1239 | << name << ") failed" << llendl; |
376 | return FALSE; | 1240 | return FALSE; |
377 | } | 1241 | } |
@@ -380,74 +1244,131 @@ BOOL LLTabContainerCommon::selectTabByName(const LLString& name) | |||
380 | return result; | 1244 | return result; |
381 | } | 1245 | } |
382 | 1246 | ||
383 | 1247 | BOOL LLTabContainer::getTabPanelFlashing(LLPanel *child) | |
384 | void LLTabContainerCommon::selectFirstTab() | ||
385 | { | 1248 | { |
386 | selectTab( 0 ); | 1249 | LLTabTuple* tuple = getTabByPanel(child); |
1250 | if( tuple ) | ||
1251 | { | ||
1252 | return tuple->mButton->getFlashing(); | ||
1253 | } | ||
1254 | return FALSE; | ||
387 | } | 1255 | } |
388 | 1256 | ||
389 | 1257 | void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state ) | |
390 | void LLTabContainerCommon::selectLastTab() | ||
391 | { | 1258 | { |
392 | selectTab( mTabList.size()-1 ); | 1259 | LLTabTuple* tuple = getTabByPanel(child); |
1260 | if( tuple ) | ||
1261 | { | ||
1262 | tuple->mButton->setFlashing( state ); | ||
1263 | } | ||
393 | } | 1264 | } |
394 | 1265 | ||
395 | 1266 | void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color) | |
396 | void LLTabContainerCommon::selectNextTab() | ||
397 | { | 1267 | { |
398 | BOOL tab_has_focus = FALSE; | 1268 | LLTabTuple* tuple = getTabByPanel(child); |
399 | if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus()) | 1269 | if( tuple ) |
400 | { | ||
401 | tab_has_focus = TRUE; | ||
402 | } | ||
403 | S32 idx = mCurrentTabIdx+1; | ||
404 | if (idx >= (S32)mTabList.size()) | ||
405 | idx = 0; | ||
406 | while (!selectTab(idx) && idx != mCurrentTabIdx) | ||
407 | { | 1270 | { |
408 | idx = (idx + 1 ) % (S32)mTabList.size(); | 1271 | tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT, color); |
1272 | |||
1273 | if (!mIsVertical) | ||
1274 | { | ||
1275 | const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); | ||
1276 | // remove current width from total tab strip width | ||
1277 | mTotalTabWidth -= tuple->mButton->getRect().getWidth(); | ||
1278 | |||
1279 | S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? | ||
1280 | tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : | ||
1281 | 0; | ||
1282 | |||
1283 | tuple->mPadding = image_overlay_width; | ||
1284 | |||
1285 | tuple->mButton->setRightHPad(6); | ||
1286 | tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), | ||
1287 | tuple->mButton->getRect().getHeight()); | ||
1288 | // add back in button width to total tab strip width | ||
1289 | mTotalTabWidth += tuple->mButton->getRect().getWidth(); | ||
1290 | |||
1291 | // tabs have changed size, might need to scroll to see current tab | ||
1292 | updateMaxScrollPos(); | ||
1293 | } | ||
409 | } | 1294 | } |
1295 | } | ||
410 | 1296 | ||
411 | if (tab_has_focus) | 1297 | void LLTabContainer::setTitle(const LLString& title) |
1298 | { | ||
1299 | if (mTitleBox) | ||
412 | { | 1300 | { |
413 | mTabList[idx]->mButton->setFocus(TRUE); | 1301 | mTitleBox->setText( title ); |
414 | } | 1302 | } |
415 | } | 1303 | } |
416 | 1304 | ||
417 | void LLTabContainerCommon::selectPrevTab() | 1305 | const LLString LLTabContainer::getPanelTitle(S32 index) |
418 | { | 1306 | { |
419 | BOOL tab_has_focus = FALSE; | 1307 | if (index >= 0 && index < (S32)mTabList.size()) |
420 | if (mCurrentTabIdx >= 0 && mTabList[mCurrentTabIdx]->mButton->hasFocus()) | ||
421 | { | 1308 | { |
422 | tab_has_focus = TRUE; | 1309 | LLButton* tab_button = mTabList[index]->mButton; |
1310 | return tab_button->getLabelSelected(); | ||
423 | } | 1311 | } |
424 | S32 idx = mCurrentTabIdx-1; | 1312 | return LLString::null; |
425 | if (idx < 0) | 1313 | } |
426 | idx = mTabList.size()-1; | 1314 | |
427 | while (!selectTab(idx) && idx != mCurrentTabIdx) | 1315 | void LLTabContainer::setTopBorderHeight(S32 height) |
1316 | { | ||
1317 | mTopBorderHeight = height; | ||
1318 | } | ||
1319 | |||
1320 | S32 LLTabContainer::getTopBorderHeight() const | ||
1321 | { | ||
1322 | return mTopBorderHeight; | ||
1323 | } | ||
1324 | |||
1325 | void LLTabContainer::setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*, bool)) | ||
1326 | { | ||
1327 | LLTabTuple* tuplep = getTabByPanel(tab); | ||
1328 | if (tuplep) | ||
428 | { | 1329 | { |
429 | idx = idx - 1; | 1330 | tuplep->mOnChangeCallback = on_tab_clicked; |
430 | if (idx < 0) | ||
431 | idx = mTabList.size()-1; | ||
432 | } | 1331 | } |
433 | if (tab_has_focus) | 1332 | } |
1333 | |||
1334 | void LLTabContainer::setTabUserData(LLPanel* tab, void* userdata) | ||
1335 | { | ||
1336 | LLTabTuple* tuplep = getTabByPanel(tab); | ||
1337 | if (tuplep) | ||
434 | { | 1338 | { |
435 | mTabList[idx]->mButton->setFocus(TRUE); | 1339 | tuplep->mUserData = userdata; |
436 | } | 1340 | } |
437 | } | 1341 | } |
438 | 1342 | ||
1343 | void LLTabContainer::setRightTabBtnOffset(S32 offset) | ||
1344 | { | ||
1345 | mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 ); | ||
1346 | mRightTabBtnOffset = offset; | ||
1347 | updateMaxScrollPos(); | ||
1348 | } | ||
439 | 1349 | ||
440 | void LLTabContainerCommon::reshape(S32 width, S32 height, BOOL called_from_parent) | 1350 | void LLTabContainer::setPanelTitle(S32 index, const LLString& title) |
441 | { | 1351 | { |
442 | LLPanel::reshape( width, height, called_from_parent ); | 1352 | if (index >= 0 && index < getTabCount()) |
1353 | { | ||
1354 | LLTabTuple* tuple = getTab(index); | ||
1355 | LLButton* tab_button = tuple->mButton; | ||
1356 | const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); | ||
1357 | mTotalTabWidth -= tab_button->getRect().getWidth(); | ||
1358 | tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight()); | ||
1359 | mTotalTabWidth += tab_button->getRect().getWidth(); | ||
1360 | tab_button->setLabelSelected(title); | ||
1361 | tab_button->setLabelUnselected(title); | ||
1362 | } | ||
443 | updateMaxScrollPos(); | 1363 | updateMaxScrollPos(); |
444 | } | 1364 | } |
445 | 1365 | ||
1366 | |||
446 | // static | 1367 | // static |
447 | void LLTabContainerCommon::onTabBtn( void* userdata ) | 1368 | void LLTabContainer::onTabBtn( void* userdata ) |
448 | { | 1369 | { |
449 | LLTabTuple* tuple = (LLTabTuple*) userdata; | 1370 | LLTabTuple* tuple = (LLTabTuple*) userdata; |
450 | LLTabContainerCommon* self = tuple->mTabContainer; | 1371 | LLTabContainer* self = tuple->mTabContainer; |
451 | self->selectTabPanel( tuple->mTabPanel ); | 1372 | self->selectTabPanel( tuple->mTabPanel ); |
452 | 1373 | ||
453 | if( tuple->mOnChangeCallback ) | 1374 | if( tuple->mOnChangeCallback ) |
@@ -459,7 +1380,7 @@ void LLTabContainerCommon::onTabBtn( void* userdata ) | |||
459 | } | 1380 | } |
460 | 1381 | ||
461 | // static | 1382 | // static |
462 | void LLTabContainerCommon::onCloseBtn( void* userdata ) | 1383 | void LLTabContainer::onCloseBtn( void* userdata ) |
463 | { | 1384 | { |
464 | LLTabContainer* self = (LLTabContainer*) userdata; | 1385 | LLTabContainer* self = (LLTabContainer*) userdata; |
465 | if( self->mCloseCallback ) | 1386 | if( self->mCloseCallback ) |
@@ -469,7 +1390,7 @@ void LLTabContainerCommon::onCloseBtn( void* userdata ) | |||
469 | } | 1390 | } |
470 | 1391 | ||
471 | // static | 1392 | // static |
472 | void LLTabContainerCommon::onNextBtn( void* userdata ) | 1393 | void LLTabContainer::onNextBtn( void* userdata ) |
473 | { | 1394 | { |
474 | // Scroll tabs to the left | 1395 | // Scroll tabs to the left |
475 | LLTabContainer* self = (LLTabContainer*) userdata; | 1396 | LLTabContainer* self = (LLTabContainer*) userdata; |
@@ -481,7 +1402,7 @@ void LLTabContainerCommon::onNextBtn( void* userdata ) | |||
481 | } | 1402 | } |
482 | 1403 | ||
483 | // static | 1404 | // static |
484 | void LLTabContainerCommon::onNextBtnHeld( void* userdata ) | 1405 | void LLTabContainer::onNextBtnHeld( void* userdata ) |
485 | { | 1406 | { |
486 | LLTabContainer* self = (LLTabContainer*) userdata; | 1407 | LLTabContainer* self = (LLTabContainer*) userdata; |
487 | if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) | 1408 | if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) |
@@ -493,7 +1414,7 @@ void LLTabContainerCommon::onNextBtnHeld( void* userdata ) | |||
493 | } | 1414 | } |
494 | 1415 | ||
495 | // static | 1416 | // static |
496 | void LLTabContainerCommon::onPrevBtn( void* userdata ) | 1417 | void LLTabContainer::onPrevBtn( void* userdata ) |
497 | { | 1418 | { |
498 | LLTabContainer* self = (LLTabContainer*) userdata; | 1419 | LLTabContainer* self = (LLTabContainer*) userdata; |
499 | if (!self->mScrolled) | 1420 | if (!self->mScrolled) |
@@ -503,26 +1424,22 @@ void LLTabContainerCommon::onPrevBtn( void* userdata ) | |||
503 | self->mScrolled = FALSE; | 1424 | self->mScrolled = FALSE; |
504 | } | 1425 | } |
505 | 1426 | ||
506 | 1427 | // static | |
507 | void LLTabContainerCommon::onJumpFirstBtn( void* userdata ) | 1428 | void LLTabContainer::onJumpFirstBtn( void* userdata ) |
508 | { | 1429 | { |
509 | LLTabContainer* self = (LLTabContainer*) userdata; | 1430 | LLTabContainer* self = (LLTabContainer*) userdata; |
510 | |||
511 | self->mScrollPos = 0; | 1431 | self->mScrollPos = 0; |
512 | |||
513 | } | 1432 | } |
514 | 1433 | ||
515 | 1434 | // static | |
516 | void LLTabContainerCommon::onJumpLastBtn( void* userdata ) | 1435 | void LLTabContainer::onJumpLastBtn( void* userdata ) |
517 | { | 1436 | { |
518 | LLTabContainer* self = (LLTabContainer*) userdata; | 1437 | LLTabContainer* self = (LLTabContainer*) userdata; |
519 | |||
520 | self->mScrollPos = self->mMaxScrollPos; | 1438 | self->mScrollPos = self->mMaxScrollPos; |
521 | } | 1439 | } |
522 | 1440 | ||
523 | |||
524 | // static | 1441 | // static |
525 | void LLTabContainerCommon::onPrevBtnHeld( void* userdata ) | 1442 | void LLTabContainer::onPrevBtnHeld( void* userdata ) |
526 | { | 1443 | { |
527 | LLTabContainer* self = (LLTabContainer*) userdata; | 1444 | LLTabContainer* self = (LLTabContainer*) userdata; |
528 | if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) | 1445 | if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) |
@@ -533,68 +1450,8 @@ void LLTabContainerCommon::onPrevBtnHeld( void* userdata ) | |||
533 | } | 1450 | } |
534 | } | 1451 | } |
535 | 1452 | ||
536 | BOOL LLTabContainerCommon::getTabPanelFlashing(LLPanel *child) | 1453 | // static |
537 | { | 1454 | LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) |
538 | LLTabTuple* tuple = getTabByPanel(child); | ||
539 | if( tuple ) | ||
540 | { | ||
541 | return tuple->mButton->getFlashing(); | ||
542 | } | ||
543 | return FALSE; | ||
544 | } | ||
545 | |||
546 | void LLTabContainerCommon::setTabPanelFlashing(LLPanel* child, BOOL state ) | ||
547 | { | ||
548 | LLTabTuple* tuple = getTabByPanel(child); | ||
549 | if( tuple ) | ||
550 | { | ||
551 | tuple->mButton->setFlashing( state ); | ||
552 | } | ||
553 | } | ||
554 | |||
555 | void LLTabContainerCommon::setTabImage(LLPanel* child, std::string img_name, const LLColor4& color) | ||
556 | { | ||
557 | LLTabTuple* tuple = getTabByPanel(child); | ||
558 | if( tuple ) | ||
559 | { | ||
560 | tuple->mButton->setImageOverlay(img_name, LLFontGL::RIGHT, color); | ||
561 | } | ||
562 | } | ||
563 | |||
564 | void LLTabContainerCommon::setTitle(const LLString& title) | ||
565 | { | ||
566 | if (mTitleBox) | ||
567 | { | ||
568 | mTitleBox->setText( title ); | ||
569 | } | ||
570 | } | ||
571 | |||
572 | const LLString LLTabContainerCommon::getPanelTitle(S32 index) | ||
573 | { | ||
574 | if (index >= 0 && index < (S32)mTabList.size()) | ||
575 | { | ||
576 | LLButton* tab_button = mTabList[index]->mButton; | ||
577 | return tab_button->getLabelSelected(); | ||
578 | } | ||
579 | return LLString::null; | ||
580 | } | ||
581 | |||
582 | void LLTabContainerCommon::setTopBorderHeight(S32 height) | ||
583 | { | ||
584 | mTopBorderHeight = height; | ||
585 | } | ||
586 | |||
587 | // Change the name of the button for the current tab. | ||
588 | void LLTabContainerCommon::setCurrentTabName(const LLString& name) | ||
589 | { | ||
590 | // Might not have a tab selected | ||
591 | if (mCurrentTabIdx < 0) return; | ||
592 | |||
593 | mTabList[mCurrentTabIdx]->mButton->setLabelSelected(name); | ||
594 | mTabList[mCurrentTabIdx]->mButton->setLabelUnselected(name); | ||
595 | } | ||
596 | |||
597 | LLView* LLTabContainerCommon::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) | ||
598 | { | 1455 | { |
599 | LLString name("tab_container"); | 1456 | LLString name("tab_container"); |
600 | node->getAttributeString("name", name); | 1457 | node->getAttributeString("name", name); |
@@ -626,58 +1483,30 @@ LLView* LLTabContainerCommon::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtr | |||
626 | BOOL border = FALSE; | 1483 | BOOL border = FALSE; |
627 | node->getAttributeBOOL("border", border); | 1484 | node->getAttributeBOOL("border", border); |
628 | 1485 | ||
629 | // Create the correct container type. | 1486 | LLTabContainer* tab_container = new LLTabContainer(name, LLRect::null, tab_position, border, is_vertical); |
630 | LLTabContainerCommon* tab_container = NULL; | 1487 | |
631 | 1488 | S32 tab_min_width = tab_container->mMinTabWidth; | |
632 | if (is_vertical) | 1489 | if (node->hasAttribute("tab_width")) |
633 | { | 1490 | { |
634 | // Vertical tabs can specify tab width | 1491 | node->getAttributeS32("tab_width", tab_min_width); |
635 | U32 tab_width = TABCNTRV_TAB_WIDTH; | ||
636 | if (node->hasAttribute("tab_width")) | ||
637 | { | ||
638 | node->getAttributeU32("tab_width", tab_width); | ||
639 | } | ||
640 | |||
641 | tab_container = new LLTabContainerVertical(name, | ||
642 | LLRect::null, | ||
643 | NULL, | ||
644 | NULL, | ||
645 | tab_width, | ||
646 | border); | ||
647 | |||
648 | } | 1492 | } |
649 | else // horizontal tab container | 1493 | else if( node->hasAttribute("tab_min_width")) |
650 | { | 1494 | { |
651 | // Horizontal tabs can have a title (?) | 1495 | node->getAttributeS32("tab_min_width", tab_min_width); |
652 | LLString title(LLString::null); | 1496 | } |
653 | if (node->hasAttribute("title")) | ||
654 | { | ||
655 | node->getAttributeString("title", title); | ||
656 | } | ||
657 | 1497 | ||
658 | tab_container = new LLTabContainer(name, | 1498 | S32 tab_max_width = tab_container->mMaxTabWidth; |
659 | LLRect::null, | 1499 | if (node->hasAttribute("tab_max_width")) |
660 | tab_position, | 1500 | { |
661 | NULL, | 1501 | node->getAttributeS32("tab_max_width", tab_max_width); |
662 | NULL, | ||
663 | title, | ||
664 | border); | ||
665 | |||
666 | if(node->hasAttribute("tab_min_width")) | ||
667 | { | ||
668 | S32 minTabWidth=0; | ||
669 | node->getAttributeS32("tab_min_width",minTabWidth); | ||
670 | ((LLTabContainer*)tab_container)->setMinTabWidth(minTabWidth); | ||
671 | } | ||
672 | if(node->hasAttribute("tab_max_width")) | ||
673 | { | ||
674 | S32 maxTabWidth=0; | ||
675 | node->getAttributeS32("tab_max_width",maxTabWidth); | ||
676 | ((LLTabContainer*)tab_container)->setMaxTabWidth(maxTabWidth); | ||
677 | } | ||
678 | } | 1502 | } |
1503 | |||
1504 | tab_container->setMinTabWidth(tab_min_width); | ||
1505 | tab_container->setMaxTabWidth(tab_max_width); | ||
679 | 1506 | ||
680 | node->getAttributeBOOL("hide_tabs", tab_container->mTabsHidden); | 1507 | BOOL hidden(tab_container->getTabsHidden()); |
1508 | node->getAttributeBOOL("hide_tabs", hidden); | ||
1509 | tab_container->setTabsHidden(hidden); | ||
681 | 1510 | ||
682 | tab_container->setPanelParameters(node, parent); | 1511 | tab_container->setPanelParameters(node, parent); |
683 | 1512 | ||
@@ -718,76 +1547,12 @@ LLView* LLTabContainerCommon::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtr | |||
718 | return tab_container; | 1547 | return tab_container; |
719 | } | 1548 | } |
720 | 1549 | ||
721 | void LLTabContainerCommon::insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point) | 1550 | // private |
722 | { | ||
723 | switch(insertion_point) | ||
724 | { | ||
725 | case START: | ||
726 | // insert the new tab in the front of the list | ||
727 | mTabList.insert(mTabList.begin() + mLockedTabCount, tuple); | ||
728 | break; | ||
729 | case LEFT_OF_CURRENT: | ||
730 | // insert the new tab before the current tab (but not before mLockedTabCount) | ||
731 | { | ||
732 | tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx); | ||
733 | mTabList.insert(current_iter, tuple); | ||
734 | } | ||
735 | break; | ||
736 | |||
737 | case RIGHT_OF_CURRENT: | ||
738 | // insert the new tab after the current tab (but not before mLockedTabCount) | ||
739 | { | ||
740 | tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1); | ||
741 | mTabList.insert(current_iter, tuple); | ||
742 | } | ||
743 | break; | ||
744 | case END: | ||
745 | default: | ||
746 | mTabList.push_back( tuple ); | ||
747 | } | ||
748 | } | ||
749 | |||
750 | |||
751 | LLTabContainer::LLTabContainer( | ||
752 | const LLString& name, const LLRect& rect, TabPosition pos, | ||
753 | void(*close_callback)(void*), void* callback_userdata, | ||
754 | const LLString& title, BOOL bordered ) | ||
755 | : | ||
756 | LLTabContainerCommon(name, rect, pos, close_callback, callback_userdata, bordered), | ||
757 | mLeftArrowBtn(NULL), | ||
758 | mJumpLeftArrowBtn(NULL), | ||
759 | mRightArrowBtn(NULL), | ||
760 | mJumpRightArrowBtn(NULL), | ||
761 | mRightTabBtnOffset(0), | ||
762 | mMinTabWidth(TABCNTR_TAB_MIN_WIDTH), | ||
763 | mMaxTabWidth(TABCNTR_TAB_MAX_WIDTH), | ||
764 | mTotalTabWidth(0) | ||
765 | { | ||
766 | initButtons( ); | ||
767 | } | ||
768 | |||
769 | LLTabContainer::LLTabContainer( | ||
770 | const LLString& name, const LLString& rect_control, TabPosition pos, | ||
771 | void(*close_callback)(void*), void* callback_userdata, | ||
772 | const LLString& title, BOOL bordered ) | ||
773 | : | ||
774 | LLTabContainerCommon(name, rect_control, pos, close_callback, callback_userdata, bordered), | ||
775 | mLeftArrowBtn(NULL), | ||
776 | mJumpLeftArrowBtn(NULL), | ||
777 | mRightArrowBtn(NULL), | ||
778 | mJumpRightArrowBtn(NULL), | ||
779 | mRightTabBtnOffset(0), | ||
780 | mMinTabWidth(TABCNTR_TAB_MIN_WIDTH), | ||
781 | mMaxTabWidth(TABCNTR_TAB_MAX_WIDTH), | ||
782 | mTotalTabWidth(0) | ||
783 | { | ||
784 | initButtons( ); | ||
785 | } | ||
786 | 1551 | ||
787 | void LLTabContainer::initButtons() | 1552 | void LLTabContainer::initButtons() |
788 | { | 1553 | { |
789 | // Hack: | 1554 | // Hack: |
790 | if (mRect.getHeight() == 0 || mLeftArrowBtn) | 1555 | if (getRect().getHeight() == 0 || mPrevArrowBtn) |
791 | { | 1556 | { |
792 | return; // Don't have a rect yet or already got called | 1557 | return; // Don't have a rect yet or already got called |
793 | } | 1558 | } |
@@ -795,881 +1560,255 @@ void LLTabContainer::initButtons() | |||
795 | LLString out_id; | 1560 | LLString out_id; |
796 | LLString in_id; | 1561 | LLString in_id; |
797 | 1562 | ||
798 | S32 arrow_fudge = 1; // match new art better | 1563 | if (mIsVertical) |
799 | |||
800 | // tabs on bottom reserve room for resize handle (just in case) | ||
801 | if (mTabPosition == BOTTOM) | ||
802 | { | 1564 | { |
803 | mRightTabBtnOffset = RESIZE_HANDLE_WIDTH; | 1565 | // Left and right scroll arrows (for when there are too many tabs to show all at once). |
804 | } | 1566 | S32 btn_top = getRect().getHeight(); |
805 | 1567 | S32 btn_top_lower = getRect().mBottom+TABCNTRV_ARROW_BTN_SIZE; | |
806 | // Left and right scroll arrows (for when there are too many tabs to show all at once). | ||
807 | S32 btn_top = (mTabPosition == TOP ) ? mRect.getHeight() - mTopBorderHeight : TABCNTR_ARROW_BTN_SIZE + 1; | ||
808 | |||
809 | LLRect left_arrow_btn_rect; | ||
810 | left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+TABCNTR_ARROW_BTN_SIZE, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE ); | ||
811 | |||
812 | LLRect jump_left_arrow_btn_rect; | ||
813 | jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE ); | ||
814 | |||
815 | S32 right_pad = TABCNTR_ARROW_BTN_SIZE + LLPANEL_BORDER_WIDTH + 1; | ||
816 | |||
817 | LLRect right_arrow_btn_rect; | ||
818 | right_arrow_btn_rect.setLeftTopAndSize( mRect.getWidth() - mRightTabBtnOffset - right_pad - TABCNTR_ARROW_BTN_SIZE, | ||
819 | btn_top + arrow_fudge, | ||
820 | TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE ); | ||
821 | 1568 | ||
1569 | LLRect up_arrow_btn_rect; | ||
1570 | up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE ); | ||
822 | 1571 | ||
823 | LLRect jump_right_arrow_btn_rect; | 1572 | LLRect down_arrow_btn_rect; |
824 | jump_right_arrow_btn_rect.setLeftTopAndSize( mRect.getWidth() - mRightTabBtnOffset - right_pad, | 1573 | down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE ); |
825 | btn_top + arrow_fudge, | ||
826 | TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE ); | ||
827 | 1574 | ||
828 | out_id = "UIImgBtnJumpLeftOutUUID"; | 1575 | out_id = "UIImgBtnScrollUpOutUUID"; |
829 | in_id = "UIImgBtnJumpLeftInUUID"; | 1576 | in_id = "UIImgBtnScrollUpInUUID"; |
830 | mJumpLeftArrowBtn = new LLButton( | 1577 | mPrevArrowBtn = new LLButton("Up Arrow", up_arrow_btn_rect, |
831 | "Jump Left Arrow", jump_left_arrow_btn_rect, | 1578 | out_id, in_id, "", |
832 | out_id, in_id, "", | 1579 | &onPrevBtn, this, NULL ); |
833 | &LLTabContainer::onJumpFirstBtn, this, LLFontGL::sSansSerif ); | 1580 | mPrevArrowBtn->setFollowsTop(); |
834 | mJumpLeftArrowBtn->setFollowsLeft(); | 1581 | mPrevArrowBtn->setFollowsLeft(); |
835 | mJumpLeftArrowBtn->setSaveToXML(false); | ||
836 | mJumpLeftArrowBtn->setTabStop(FALSE); | ||
837 | addChild(mJumpLeftArrowBtn); | ||
838 | 1582 | ||
839 | out_id = "UIImgBtnScrollLeftOutUUID"; | 1583 | out_id = "UIImgBtnScrollDownOutUUID"; |
840 | in_id = "UIImgBtnScrollLeftInUUID"; | 1584 | in_id = "UIImgBtnScrollDownInUUID"; |
841 | mLeftArrowBtn = new LLButton( | 1585 | mNextArrowBtn = new LLButton("Down Arrow", down_arrow_btn_rect, |
842 | "Left Arrow", left_arrow_btn_rect, | 1586 | out_id, in_id, "", |
843 | out_id, in_id, "", | 1587 | &onNextBtn, this, NULL ); |
844 | &LLTabContainer::onPrevBtn, this, LLFontGL::sSansSerif ); | 1588 | mNextArrowBtn->setFollowsBottom(); |
845 | mLeftArrowBtn->setHeldDownCallback(onPrevBtnHeld); | 1589 | mNextArrowBtn->setFollowsLeft(); |
846 | mLeftArrowBtn->setFollowsLeft(); | ||
847 | mLeftArrowBtn->setSaveToXML(false); | ||
848 | mLeftArrowBtn->setTabStop(FALSE); | ||
849 | addChild(mLeftArrowBtn); | ||
850 | |||
851 | out_id = "UIImgBtnJumpRightOutUUID"; | ||
852 | in_id = "UIImgBtnJumpRightInUUID"; | ||
853 | mJumpRightArrowBtn = new LLButton( | ||
854 | "Jump Right Arrow", jump_right_arrow_btn_rect, | ||
855 | out_id, in_id, "", | ||
856 | &LLTabContainer::onJumpLastBtn, this, | ||
857 | LLFontGL::sSansSerif); | ||
858 | mJumpRightArrowBtn->setFollowsRight(); | ||
859 | mJumpRightArrowBtn->setSaveToXML(false); | ||
860 | mJumpRightArrowBtn->setTabStop(FALSE); | ||
861 | addChild(mJumpRightArrowBtn); | ||
862 | |||
863 | out_id = "UIImgBtnScrollRightOutUUID"; | ||
864 | in_id = "UIImgBtnScrollRightInUUID"; | ||
865 | mRightArrowBtn = new LLButton( | ||
866 | "Right Arrow", right_arrow_btn_rect, | ||
867 | out_id, in_id, "", | ||
868 | &LLTabContainer::onNextBtn, this, | ||
869 | LLFontGL::sSansSerif); | ||
870 | mRightArrowBtn->setFollowsRight(); | ||
871 | mRightArrowBtn->setHeldDownCallback(onNextBtnHeld); | ||
872 | mRightArrowBtn->setSaveToXML(false); | ||
873 | mRightArrowBtn->setTabStop(FALSE); | ||
874 | addChild(mRightArrowBtn); | ||
875 | |||
876 | |||
877 | if( mTabPosition == TOP ) | ||
878 | { | ||
879 | mRightArrowBtn->setFollowsTop(); | ||
880 | mLeftArrowBtn->setFollowsTop(); | ||
881 | mJumpLeftArrowBtn->setFollowsTop(); | ||
882 | mJumpRightArrowBtn->setFollowsTop(); | ||
883 | } | 1590 | } |
884 | else | 1591 | else // Horizontal |
885 | { | 1592 | { |
886 | mRightArrowBtn->setFollowsBottom(); | 1593 | S32 arrow_fudge = 1; // match new art better |
887 | mLeftArrowBtn->setFollowsBottom(); | ||
888 | mJumpLeftArrowBtn->setFollowsBottom(); | ||
889 | mJumpRightArrowBtn->setFollowsBottom(); | ||
890 | } | ||
891 | |||
892 | // set default tab group to be panel contents | ||
893 | mDefaultTabGroup = 1; | ||
894 | } | ||
895 | 1594 | ||
896 | LLTabContainer::~LLTabContainer() | 1595 | // tabs on bottom reserve room for resize handle (just in case) |
897 | { | 1596 | if (getTabPosition() == BOTTOM) |
898 | } | 1597 | { |
899 | 1598 | mRightTabBtnOffset = RESIZE_HANDLE_WIDTH; | |
900 | void LLTabContainer::addTabPanel(LLPanel* child, | 1599 | } |
901 | const LLString& label, | ||
902 | BOOL select, | ||
903 | void (*on_tab_clicked)(void*, bool), | ||
904 | void* userdata, | ||
905 | S32 indent, | ||
906 | BOOL placeholder, | ||
907 | eInsertionPoint insertion_point) | ||
908 | { | ||
909 | if (child->getParent() == this) | ||
910 | { | ||
911 | // already a child of mine | ||
912 | return; | ||
913 | } | ||
914 | const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); | ||
915 | 1600 | ||
916 | // Store the original label for possible xml export. | 1601 | // Left and right scroll arrows (for when there are too many tabs to show all at once). |
917 | child->setLabel(label); | 1602 | S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : TABCNTR_ARROW_BTN_SIZE + 1; |
918 | LLString trimmed_label = label; | ||
919 | LLString::trim(trimmed_label); | ||
920 | 1603 | ||
921 | S32 button_width = llclamp(font->getWidth(trimmed_label) + TAB_PADDING, mMinTabWidth, mMaxTabWidth); | 1604 | LLRect left_arrow_btn_rect; |
1605 | left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+TABCNTR_ARROW_BTN_SIZE, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE ); | ||
922 | 1606 | ||
923 | // Tab panel | 1607 | LLRect jump_left_arrow_btn_rect; |
924 | S32 tab_panel_top; | 1608 | jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE ); |
925 | S32 tab_panel_bottom; | ||
926 | if( LLTabContainer::TOP == mTabPosition ) | ||
927 | { | ||
928 | tab_panel_top = mRect.getHeight() - mTopBorderHeight - (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP); | ||
929 | tab_panel_bottom = LLPANEL_BORDER_WIDTH; | ||
930 | } | ||
931 | else | ||
932 | { | ||
933 | tab_panel_top = mRect.getHeight() - mTopBorderHeight; | ||
934 | tab_panel_bottom = (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP); // Run to the edge, covering up the border | ||
935 | } | ||
936 | |||
937 | LLRect tab_panel_rect( | ||
938 | LLPANEL_BORDER_WIDTH, | ||
939 | tab_panel_top, | ||
940 | mRect.getWidth()-LLPANEL_BORDER_WIDTH, | ||
941 | tab_panel_bottom ); | ||
942 | 1609 | ||
943 | child->setFollowsAll(); | 1610 | S32 right_pad = TABCNTR_ARROW_BTN_SIZE + LLPANEL_BORDER_WIDTH + 1; |
944 | child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom); | ||
945 | child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE ); | ||
946 | child->setBackgroundVisible( FALSE ); // No need to overdraw | ||
947 | // add this child later | ||
948 | 1611 | ||
949 | child->setVisible( FALSE ); // Will be made visible when selected | 1612 | LLRect right_arrow_btn_rect; |
1613 | right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - TABCNTR_ARROW_BTN_SIZE, | ||
1614 | btn_top + arrow_fudge, | ||
1615 | TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE ); | ||
950 | 1616 | ||
951 | mTotalTabWidth += button_width; | ||
952 | 1617 | ||
953 | // Tab button | 1618 | LLRect jump_right_arrow_btn_rect; |
954 | LLRect btn_rect; // Note: btn_rect.mLeft is just a dummy. Will be updated in draw(). | 1619 | jump_right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad, |
955 | LLString tab_img; | 1620 | btn_top + arrow_fudge, |
956 | LLString tab_selected_img; | 1621 | TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE ); |
957 | S32 tab_fudge = 1; // To make new tab art look better, nudge buttons up 1 pel | ||
958 | 1622 | ||
959 | if( LLTabContainer::TOP == mTabPosition ) | 1623 | out_id = "UIImgBtnJumpLeftOutUUID"; |
960 | { | 1624 | in_id = "UIImgBtnJumpLeftInUUID"; |
961 | btn_rect.setLeftTopAndSize( 0, mRect.getHeight() - mTopBorderHeight + tab_fudge, button_width, TABCNTR_TAB_HEIGHT ); | 1625 | mJumpPrevArrowBtn = new LLButton("Jump Left Arrow", jump_left_arrow_btn_rect, |
962 | tab_img = "tab_top_blue.tga"; | 1626 | out_id, in_id, "", |
963 | tab_selected_img = "tab_top_selected_blue.tga"; | 1627 | &LLTabContainer::onJumpFirstBtn, this, LLFontGL::sSansSerif ); |
964 | } | 1628 | mJumpPrevArrowBtn->setFollowsLeft(); |
965 | else | ||
966 | { | ||
967 | btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, TABCNTR_TAB_HEIGHT ); | ||
968 | tab_img = "tab_bottom_blue.tga"; | ||
969 | tab_selected_img = "tab_bottom_selected_blue.tga"; | ||
970 | } | ||
971 | 1629 | ||
972 | if (placeholder) | 1630 | out_id = "UIImgBtnScrollLeftOutUUID"; |
973 | { | 1631 | in_id = "UIImgBtnScrollLeftInUUID"; |
974 | // *FIX: wont work for horizontal tabs | 1632 | mPrevArrowBtn = new LLButton("Left Arrow", left_arrow_btn_rect, |
975 | btn_rect.translate(0, -LLBUTTON_V_PAD-2); | 1633 | out_id, in_id, "", |
976 | LLString box_label = trimmed_label; | 1634 | &LLTabContainer::onPrevBtn, this, LLFontGL::sSansSerif ); |
977 | LLTextBox* text = new LLTextBox(box_label, btn_rect, box_label, font); | 1635 | mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld); |
978 | addChild( text, 0 ); | 1636 | mPrevArrowBtn->setFollowsLeft(); |
979 | 1637 | ||
980 | LLButton* btn = new LLButton("", LLRect(0,0,0,0)); | 1638 | out_id = "UIImgBtnJumpRightOutUUID"; |
981 | LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata, text ); | 1639 | in_id = "UIImgBtnJumpRightInUUID"; |
982 | addChild( btn, 0 ); | 1640 | mJumpNextArrowBtn = new LLButton("Jump Right Arrow", jump_right_arrow_btn_rect, |
983 | addChild( child, 1 ); | 1641 | out_id, in_id, "", |
984 | insertTuple(tuple, insertion_point); | 1642 | &LLTabContainer::onJumpLastBtn, this, |
985 | } | 1643 | LLFontGL::sSansSerif); |
986 | else | 1644 | mJumpNextArrowBtn->setFollowsRight(); |
987 | { | 1645 | |
988 | LLString tooltip = trimmed_label; | 1646 | out_id = "UIImgBtnScrollRightOutUUID"; |
989 | tooltip += "\nAlt-Left arrow for previous tab"; | 1647 | in_id = "UIImgBtnScrollRightInUUID"; |
990 | tooltip += "\nAlt-Right arrow for next tab"; | 1648 | mNextArrowBtn = new LLButton("Right Arrow", right_arrow_btn_rect, |
991 | 1649 | out_id, in_id, "", | |
992 | LLButton* btn = new LLButton( | 1650 | &LLTabContainer::onNextBtn, this, |
993 | LLString(child->getName()) + " tab", | 1651 | LLFontGL::sSansSerif); |
994 | btn_rect, | 1652 | mNextArrowBtn->setFollowsRight(); |
995 | "", "", "", | 1653 | |
996 | &LLTabContainer::onTabBtn, NULL, // set userdata below | 1654 | if( getTabPosition() == TOP ) |
997 | font, | ||
998 | trimmed_label, trimmed_label ); | ||
999 | btn->setSaveToXML(false); | ||
1000 | btn->setVisible( FALSE ); | ||
1001 | btn->setToolTip( tooltip ); | ||
1002 | btn->setScaleImage(TRUE); | ||
1003 | btn->setImages(tab_img, tab_selected_img); | ||
1004 | |||
1005 | // Try to squeeze in a bit more text | ||
1006 | btn->setLeftHPad( 4 ); | ||
1007 | btn->setRightHPad( 2 ); | ||
1008 | btn->setHAlign(LLFontGL::LEFT); | ||
1009 | btn->setTabStop(FALSE); | ||
1010 | if (indent) | ||
1011 | { | ||
1012 | btn->setLeftHPad(indent); | ||
1013 | } | ||
1014 | |||
1015 | if( mTabPosition == TOP ) | ||
1016 | { | 1655 | { |
1017 | btn->setFollowsTop(); | 1656 | mNextArrowBtn->setFollowsTop(); |
1657 | mPrevArrowBtn->setFollowsTop(); | ||
1658 | mJumpPrevArrowBtn->setFollowsTop(); | ||
1659 | mJumpNextArrowBtn->setFollowsTop(); | ||
1018 | } | 1660 | } |
1019 | else | 1661 | else |
1020 | { | 1662 | { |
1021 | btn->setFollowsBottom(); | 1663 | mNextArrowBtn->setFollowsBottom(); |
1664 | mPrevArrowBtn->setFollowsBottom(); | ||
1665 | mJumpPrevArrowBtn->setFollowsBottom(); | ||
1666 | mJumpNextArrowBtn->setFollowsBottom(); | ||
1022 | } | 1667 | } |
1023 | |||
1024 | LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata ); | ||
1025 | btn->setCallbackUserData( tuple ); | ||
1026 | addChild( btn, 0 ); | ||
1027 | addChild( child, 1 ); | ||
1028 | insertTuple(tuple, insertion_point); | ||
1029 | } | 1668 | } |
1030 | 1669 | ||
1031 | updateMaxScrollPos(); | 1670 | mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld); |
1671 | mPrevArrowBtn->setSaveToXML(false); | ||
1672 | mPrevArrowBtn->setTabStop(FALSE); | ||
1673 | addChild(mPrevArrowBtn); | ||
1032 | 1674 | ||
1033 | if( select ) | 1675 | mNextArrowBtn->setHeldDownCallback(onNextBtnHeld); |
1676 | mNextArrowBtn->setSaveToXML(false); | ||
1677 | mNextArrowBtn->setTabStop(FALSE); | ||
1678 | addChild(mNextArrowBtn); | ||
1679 | |||
1680 | if (mJumpPrevArrowBtn) | ||
1034 | { | 1681 | { |
1035 | selectLastTab(); | 1682 | mJumpPrevArrowBtn->setSaveToXML(false); |
1683 | mJumpPrevArrowBtn->setTabStop(FALSE); | ||
1684 | addChild(mJumpPrevArrowBtn); | ||
1036 | } | 1685 | } |
1686 | |||
1687 | if (mJumpNextArrowBtn) | ||
1688 | { | ||
1689 | mJumpNextArrowBtn->setSaveToXML(false); | ||
1690 | mJumpNextArrowBtn->setTabStop(FALSE); | ||
1691 | addChild(mJumpNextArrowBtn); | ||
1692 | } | ||
1693 | |||
1694 | // set default tab group to be panel contents | ||
1695 | setDefaultTabGroup(1); | ||
1037 | } | 1696 | } |
1038 | 1697 | ||
1039 | void LLTabContainer::removeTabPanel(LLPanel* child) | 1698 | LLTabContainer::LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child) |
1040 | { | 1699 | { |
1041 | // Adjust the total tab width. | ||
1042 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | 1700 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) |
1043 | { | 1701 | { |
1044 | LLTabTuple* tuple = *iter; | 1702 | LLTabTuple* tuple = *iter; |
1045 | if( tuple->mTabPanel == child ) | 1703 | if( tuple->mTabPanel == child ) |
1046 | { | 1704 | { |
1047 | mTotalTabWidth -= tuple->mButton->getRect().getWidth(); | 1705 | return tuple; |
1048 | break; | ||
1049 | } | 1706 | } |
1050 | } | 1707 | } |
1051 | 1708 | return NULL; | |
1052 | LLTabContainerCommon::removeTabPanel(child); | ||
1053 | } | ||
1054 | |||
1055 | void LLTabContainer::setPanelTitle(S32 index, const LLString& title) | ||
1056 | { | ||
1057 | if (index >= 0 && index < (S32)mTabList.size()) | ||
1058 | { | ||
1059 | LLTabTuple* tuple = mTabList[index]; | ||
1060 | LLButton* tab_button = tuple->mButton; | ||
1061 | const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); | ||
1062 | mTotalTabWidth -= tab_button->getRect().getWidth(); | ||
1063 | tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight()); | ||
1064 | mTotalTabWidth += tab_button->getRect().getWidth(); | ||
1065 | tab_button->setLabelSelected(title); | ||
1066 | tab_button->setLabelUnselected(title); | ||
1067 | } | ||
1068 | updateMaxScrollPos(); | ||
1069 | } | 1709 | } |
1070 | 1710 | ||
1071 | 1711 | void LLTabContainer::insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point) | |
1072 | void LLTabContainer::updateMaxScrollPos() | ||
1073 | { | 1712 | { |
1074 | S32 tab_space = 0; | 1713 | switch(insertion_point) |
1075 | S32 available_space = 0; | ||
1076 | tab_space = mTotalTabWidth; | ||
1077 | available_space = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_TAB_H_PAD); | ||
1078 | |||
1079 | if( tab_space > available_space ) | ||
1080 | { | 1714 | { |
1081 | S32 available_width_with_arrows = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1); | 1715 | case START: |
1082 | // subtract off reserved portion on left | 1716 | // insert the new tab in the front of the list |
1083 | available_width_with_arrows -= TABCNTR_TAB_PARTIAL_WIDTH; | 1717 | mTabList.insert(mTabList.begin() + mLockedTabCount, tuple); |
1084 | 1718 | break; | |
1085 | S32 running_tab_width = 0; | 1719 | case LEFT_OF_CURRENT: |
1086 | mMaxScrollPos = mTabList.size(); | 1720 | // insert the new tab before the current tab (but not before mLockedTabCount) |
1087 | for(tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(); tab_it != mTabList.rend(); ++tab_it) | ||
1088 | { | 1721 | { |
1089 | running_tab_width += (*tab_it)->mButton->getRect().getWidth(); | 1722 | tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx); |
1090 | if (running_tab_width > available_width_with_arrows) | 1723 | mTabList.insert(current_iter, tuple); |
1091 | { | ||
1092 | break; | ||
1093 | } | ||
1094 | mMaxScrollPos--; | ||
1095 | } | 1724 | } |
1096 | // in case last tab doesn't actually fit on screen, make it the last scrolling position | 1725 | break; |
1097 | mMaxScrollPos = llmin(mMaxScrollPos, (S32)mTabList.size() - 1); | ||
1098 | } | ||
1099 | else | ||
1100 | { | ||
1101 | mMaxScrollPos = 0; | ||
1102 | mScrollPos = 0; | ||
1103 | } | ||
1104 | if (mScrollPos > mMaxScrollPos) | ||
1105 | { | ||
1106 | mScrollPos = mMaxScrollPos; | ||
1107 | } | ||
1108 | } | ||
1109 | 1726 | ||
1110 | void LLTabContainer::commitHoveredButton(S32 x, S32 y) | 1727 | case RIGHT_OF_CURRENT: |
1111 | { | 1728 | // insert the new tab after the current tab (but not before mLockedTabCount) |
1112 | if (hasMouseCapture()) | ||
1113 | { | ||
1114 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
1115 | { | 1729 | { |
1116 | LLTabTuple* tuple = *iter; | 1730 | tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1); |
1117 | tuple->mButton->setVisible( TRUE ); | 1731 | mTabList.insert(current_iter, tuple); |
1118 | S32 local_x = x - tuple->mButton->getRect().mLeft; | ||
1119 | S32 local_y = y - tuple->mButton->getRect().mBottom; | ||
1120 | if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) | ||
1121 | { | ||
1122 | tuple->mButton->onCommit(); | ||
1123 | } | ||
1124 | } | 1732 | } |
1733 | break; | ||
1734 | case END: | ||
1735 | default: | ||
1736 | mTabList.push_back( tuple ); | ||
1125 | } | 1737 | } |
1126 | } | 1738 | } |
1127 | 1739 | ||
1128 | void LLTabContainer::setMinTabWidth(S32 width) | ||
1129 | { | ||
1130 | mMinTabWidth = width; | ||
1131 | } | ||
1132 | |||
1133 | void LLTabContainer::setMaxTabWidth(S32 width) | ||
1134 | { | ||
1135 | mMaxTabWidth = width; | ||
1136 | } | ||
1137 | |||
1138 | S32 LLTabContainer::getMinTabWidth() const | ||
1139 | { | ||
1140 | return mMinTabWidth; | ||
1141 | } | ||
1142 | 1740 | ||
1143 | S32 LLTabContainer::getMaxTabWidth() const | ||
1144 | { | ||
1145 | return mMaxTabWidth; | ||
1146 | } | ||
1147 | 1741 | ||
1148 | BOOL LLTabContainer::selectTab(S32 which) | 1742 | void LLTabContainer::updateMaxScrollPos() |
1149 | { | 1743 | { |
1150 | if (which >= (S32)mTabList.size()) return FALSE; | 1744 | BOOL no_scroll = TRUE; |
1151 | if (which < 0) return FALSE; | 1745 | if (mIsVertical) |
1152 | |||
1153 | //if( gFocusMgr.childHasKeyboardFocus( this ) ) | ||
1154 | //{ | ||
1155 | // gFocusMgr.setKeyboardFocus( NULL ); | ||
1156 | //} | ||
1157 | |||
1158 | LLTabTuple* selected_tuple = mTabList[which]; | ||
1159 | if (!selected_tuple) | ||
1160 | { | ||
1161 | return FALSE; | ||
1162 | } | ||
1163 | |||
1164 | if (mTabList[which]->mButton->getEnabled()) | ||
1165 | { | 1746 | { |
1166 | mCurrentTabIdx = which; | 1747 | S32 tab_total_height = (BTN_HEIGHT + TABCNTRV_PAD) * getTabCount(); |
1167 | 1748 | S32 available_height = getRect().getHeight() - getTopBorderHeight(); | |
1168 | S32 i = 0; | 1749 | if( tab_total_height > available_height ) |
1169 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
1170 | { | 1750 | { |
1171 | LLTabTuple* tuple = *iter; | 1751 | S32 available_height_with_arrows = getRect().getHeight() - 2*(TABCNTRV_ARROW_BTN_SIZE + 3*TABCNTRV_PAD); |
1172 | BOOL is_selected = ( tuple == selected_tuple ); | 1752 | S32 additional_needed = tab_total_height - available_height_with_arrows; |
1173 | tuple->mTabPanel->setVisible( is_selected ); | 1753 | setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) ); |
1174 | // tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. | 1754 | no_scroll = FALSE; |
1175 | tuple->mButton->setToggleState( is_selected ); | ||
1176 | // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs | ||
1177 | tuple->mButton->setTabStop( is_selected ); | ||
1178 | |||
1179 | if( is_selected && mMaxScrollPos > 0) | ||
1180 | { | ||
1181 | // Make sure selected tab is within scroll region | ||
1182 | if( i < mScrollPos ) | ||
1183 | { | ||
1184 | mScrollPos = i; | ||
1185 | } | ||
1186 | else | ||
1187 | { | ||
1188 | S32 available_width_with_arrows = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1); | ||
1189 | S32 running_tab_width = tuple->mButton->getRect().getWidth(); | ||
1190 | S32 j = i - 1; | ||
1191 | S32 min_scroll_pos = i; | ||
1192 | if (running_tab_width < available_width_with_arrows) | ||
1193 | { | ||
1194 | while (j >= 0) | ||
1195 | { | ||
1196 | LLTabTuple* other_tuple = mTabList[j]; | ||
1197 | running_tab_width += other_tuple->mButton->getRect().getWidth(); | ||
1198 | if (running_tab_width > available_width_with_arrows) | ||
1199 | { | ||
1200 | break; | ||
1201 | } | ||
1202 | j--; | ||
1203 | } | ||
1204 | min_scroll_pos = j + 1; | ||
1205 | } | ||
1206 | mScrollPos = llclamp(mScrollPos, min_scroll_pos, i); | ||
1207 | mScrollPos = llmin(mScrollPos, mMaxScrollPos); | ||
1208 | } | ||
1209 | } | ||
1210 | i++; | ||
1211 | } | ||
1212 | if( selected_tuple->mOnChangeCallback ) | ||
1213 | { | ||
1214 | selected_tuple->mOnChangeCallback( selected_tuple->mUserData, false ); | ||
1215 | } | 1755 | } |
1216 | return TRUE; | ||
1217 | } | 1756 | } |
1218 | else | 1757 | else |
1219 | { | 1758 | { |
1220 | return FALSE; | 1759 | S32 tab_space = 0; |
1221 | } | 1760 | S32 available_space = 0; |
1222 | } | 1761 | tab_space = mTotalTabWidth; |
1762 | available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_TAB_H_PAD); | ||
1223 | 1763 | ||
1224 | void LLTabContainer::draw() | 1764 | if( tab_space > available_space ) |
1225 | { | ||
1226 | S32 target_pixel_scroll = 0; | ||
1227 | S32 cur_scroll_pos = mScrollPos; | ||
1228 | if (cur_scroll_pos > 0) | ||
1229 | { | ||
1230 | S32 available_width_with_arrows = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1); | ||
1231 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
1232 | { | 1765 | { |
1233 | if (cur_scroll_pos == 0) | 1766 | S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1); |
1234 | { | 1767 | // subtract off reserved portion on left |
1235 | break; | 1768 | available_width_with_arrows -= TABCNTR_TAB_PARTIAL_WIDTH; |
1236 | } | ||
1237 | target_pixel_scroll += (*iter)->mButton->getRect().getWidth(); | ||
1238 | cur_scroll_pos--; | ||
1239 | } | ||
1240 | 1769 | ||
1241 | // Show part of the tab to the left of what is fully visible | 1770 | S32 running_tab_width = 0; |
1242 | target_pixel_scroll -= TABCNTR_TAB_PARTIAL_WIDTH; | 1771 | setMaxScrollPos(getTabCount()); |
1243 | // clamp so that rightmost tab never leaves right side of screen | 1772 | for(tuple_list_t::reverse_iterator tab_it = mTabList.rbegin(); tab_it != mTabList.rend(); ++tab_it) |
1244 | target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows, target_pixel_scroll); | ||
1245 | } | ||
1246 | |||
1247 | mScrollPosPixels = (S32)lerp((F32)mScrollPosPixels, (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f)); | ||
1248 | if( getVisible() ) | ||
1249 | { | ||
1250 | BOOL has_scroll_arrows = (mMaxScrollPos > 0) || (mScrollPosPixels > 0); | ||
1251 | mJumpLeftArrowBtn->setVisible( has_scroll_arrows ); | ||
1252 | mJumpRightArrowBtn->setVisible( has_scroll_arrows ); | ||
1253 | mLeftArrowBtn->setVisible( has_scroll_arrows ); | ||
1254 | mRightArrowBtn->setVisible( has_scroll_arrows ); | ||
1255 | |||
1256 | // Set the leftmost position of the tab buttons. | ||
1257 | S32 left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (TABCNTR_ARROW_BTN_SIZE * 2) : TABCNTR_TAB_H_PAD); | ||
1258 | left -= mScrollPosPixels; | ||
1259 | |||
1260 | // Hide all the buttons | ||
1261 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
1262 | { | ||
1263 | LLTabTuple* tuple = *iter; | ||
1264 | tuple->mButton->setVisible( FALSE ); | ||
1265 | } | ||
1266 | |||
1267 | LLPanel::draw(); | ||
1268 | |||
1269 | // if tabs are hidden, don't draw them and leave them in the invisible state | ||
1270 | if (!mTabsHidden) | ||
1271 | { | ||
1272 | // Show all the buttons | ||
1273 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
1274 | { | ||
1275 | LLTabTuple* tuple = *iter; | ||
1276 | tuple->mButton->setVisible( TRUE ); | ||
1277 | } | ||
1278 | |||
1279 | // Draw some of the buttons... | ||
1280 | LLRect clip_rect = getLocalRect(); | ||
1281 | if (has_scroll_arrows) | ||
1282 | { | 1773 | { |
1283 | // ...but clip them. | 1774 | running_tab_width += (*tab_it)->mButton->getRect().getWidth(); |
1284 | clip_rect.mLeft = mLeftArrowBtn->getRect().mRight; | 1775 | if (running_tab_width > available_width_with_arrows) |
1285 | clip_rect.mRight = mRightArrowBtn->getRect().mLeft; | ||
1286 | } | ||
1287 | LLLocalClipRect clip(clip_rect); | ||
1288 | |||
1289 | S32 max_scroll_visible = mTabList.size() - mMaxScrollPos + mScrollPos; | ||
1290 | S32 idx = 0; | ||
1291 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
1292 | { | ||
1293 | LLTabTuple* tuple = *iter; | ||
1294 | |||
1295 | tuple->mButton->translate( left - tuple->mButton->getRect().mLeft, 0 ); | ||
1296 | left += tuple->mButton->getRect().getWidth(); | ||
1297 | |||
1298 | if( idx < mScrollPos ) | ||
1299 | { | ||
1300 | if( tuple->mButton->getFlashing() ) | ||
1301 | { | ||
1302 | mLeftArrowBtn->setFlashing( TRUE ); | ||
1303 | } | ||
1304 | } | ||
1305 | else | ||
1306 | if( max_scroll_visible < idx ) | ||
1307 | { | 1776 | { |
1308 | if( tuple->mButton->getFlashing() ) | 1777 | break; |
1309 | { | ||
1310 | mRightArrowBtn->setFlashing( TRUE ); | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | LLUI::pushMatrix(); | ||
1315 | { | ||
1316 | LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); | ||
1317 | tuple->mButton->draw(); | ||
1318 | } | 1778 | } |
1319 | LLUI::popMatrix(); | 1779 | setMaxScrollPos(getMaxScrollPos()-1); |
1320 | |||
1321 | idx++; | ||
1322 | } | 1780 | } |
1781 | // in case last tab doesn't actually fit on screen, make it the last scrolling position | ||
1782 | setMaxScrollPos(llmin(getMaxScrollPos(), getTabCount() - 1)); | ||
1783 | no_scroll = FALSE; | ||
1323 | } | 1784 | } |
1324 | |||
1325 | mLeftArrowBtn->setFlashing(FALSE); | ||
1326 | mRightArrowBtn->setFlashing(FALSE); | ||
1327 | } | 1785 | } |
1328 | } | 1786 | if (no_scroll) |
1329 | |||
1330 | |||
1331 | void LLTabContainer::setRightTabBtnOffset(S32 offset) | ||
1332 | { | ||
1333 | mRightArrowBtn->translate( -offset - mRightTabBtnOffset, 0 ); | ||
1334 | mRightTabBtnOffset = offset; | ||
1335 | updateMaxScrollPos(); | ||
1336 | } | ||
1337 | |||
1338 | BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) | ||
1339 | { | ||
1340 | BOOL handled = FALSE; | ||
1341 | BOOL has_scroll_arrows = (mMaxScrollPos > 0); | ||
1342 | |||
1343 | if (has_scroll_arrows) | ||
1344 | { | ||
1345 | if (mJumpLeftArrowBtn->getRect().pointInRect(x, y)) | ||
1346 | { | ||
1347 | S32 local_x = x - mJumpLeftArrowBtn->getRect().mLeft; | ||
1348 | S32 local_y = y - mJumpLeftArrowBtn->getRect().mBottom; | ||
1349 | handled = mJumpLeftArrowBtn->handleMouseDown(local_x, local_y, mask); | ||
1350 | } | ||
1351 | if (mJumpRightArrowBtn->getRect().pointInRect(x, y)) | ||
1352 | { | ||
1353 | S32 local_x = x - mJumpRightArrowBtn->getRect().mLeft; | ||
1354 | S32 local_y = y - mJumpRightArrowBtn->getRect().mBottom; | ||
1355 | handled = mJumpRightArrowBtn->handleMouseDown(local_x, local_y, mask); | ||
1356 | } | ||
1357 | if (mLeftArrowBtn->getRect().pointInRect(x, y)) | ||
1358 | { | ||
1359 | S32 local_x = x - mLeftArrowBtn->getRect().mLeft; | ||
1360 | S32 local_y = y - mLeftArrowBtn->getRect().mBottom; | ||
1361 | handled = mLeftArrowBtn->handleMouseDown(local_x, local_y, mask); | ||
1362 | } | ||
1363 | else if (mRightArrowBtn->getRect().pointInRect(x, y)) | ||
1364 | { | ||
1365 | S32 local_x = x - mRightArrowBtn->getRect().mLeft; | ||
1366 | S32 local_y = y - mRightArrowBtn->getRect().mBottom; | ||
1367 | handled = mRightArrowBtn->handleMouseDown(local_x, local_y, mask); | ||
1368 | } | ||
1369 | } | ||
1370 | if (!handled) | ||
1371 | { | 1787 | { |
1372 | handled = LLPanel::handleMouseDown( x, y, mask ); | 1788 | setMaxScrollPos(0); |
1373 | } | 1789 | setScrollPos(0); |
1374 | |||
1375 | if (mTabList.size() > 0) | ||
1376 | { | ||
1377 | LLTabTuple* firsttuple = mTabList[0]; | ||
1378 | LLRect tab_rect(has_scroll_arrows ? mLeftArrowBtn->getRect().mRight : mJumpLeftArrowBtn->getRect().mLeft, | ||
1379 | firsttuple->mButton->getRect().mTop, | ||
1380 | has_scroll_arrows ? mRightArrowBtn->getRect().mLeft : mJumpRightArrowBtn->getRect().mRight, | ||
1381 | firsttuple->mButton->getRect().mBottom ); | ||
1382 | if( tab_rect.pointInRect( x, y ) ) | ||
1383 | { | ||
1384 | LLButton* tab_button = mTabList[getCurrentPanelIndex()]->mButton; | ||
1385 | gFocusMgr.setMouseCapture(this); | ||
1386 | gFocusMgr.setKeyboardFocus(tab_button); | ||
1387 | } | ||
1388 | } | ||
1389 | return handled; | ||
1390 | } | ||
1391 | |||
1392 | BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask ) | ||
1393 | { | ||
1394 | BOOL handled = FALSE; | ||
1395 | BOOL has_scroll_arrows = (mMaxScrollPos > 0); | ||
1396 | |||
1397 | if (has_scroll_arrows) | ||
1398 | { | ||
1399 | if (mJumpLeftArrowBtn->getRect().pointInRect(x, y)) | ||
1400 | { | ||
1401 | S32 local_x = x - mJumpLeftArrowBtn->getRect().mLeft; | ||
1402 | S32 local_y = y - mJumpLeftArrowBtn->getRect().mBottom; | ||
1403 | handled = mJumpLeftArrowBtn->handleHover(local_x, local_y, mask); | ||
1404 | } | ||
1405 | if (mJumpRightArrowBtn->getRect().pointInRect(x, y)) | ||
1406 | { | ||
1407 | S32 local_x = x - mJumpRightArrowBtn->getRect().mLeft; | ||
1408 | S32 local_y = y - mJumpRightArrowBtn->getRect().mBottom; | ||
1409 | handled = mJumpRightArrowBtn->handleHover(local_x, local_y, mask); | ||
1410 | } | ||
1411 | if (mLeftArrowBtn->getRect().pointInRect(x, y)) | ||
1412 | { | ||
1413 | S32 local_x = x - mLeftArrowBtn->getRect().mLeft; | ||
1414 | S32 local_y = y - mLeftArrowBtn->getRect().mBottom; | ||
1415 | handled = mLeftArrowBtn->handleHover(local_x, local_y, mask); | ||
1416 | } | ||
1417 | else if (mRightArrowBtn->getRect().pointInRect(x, y)) | ||
1418 | { | ||
1419 | S32 local_x = x - mRightArrowBtn->getRect().mLeft; | ||
1420 | S32 local_y = y - mRightArrowBtn->getRect().mBottom; | ||
1421 | handled = mRightArrowBtn->handleHover(local_x, local_y, mask); | ||
1422 | } | ||
1423 | } | 1790 | } |
1424 | if (!handled) | 1791 | if (getScrollPos() > getMaxScrollPos()) |
1425 | { | 1792 | { |
1426 | handled = LLPanel::handleHover(x, y, mask); | 1793 | setScrollPos(getMaxScrollPos()); // maybe just enforce this via limits in setScrollPos instead? |
1427 | } | 1794 | } |
1428 | |||
1429 | commitHoveredButton(x, y); | ||
1430 | return handled; | ||
1431 | } | 1795 | } |
1432 | 1796 | ||
1433 | BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) | 1797 | void LLTabContainer::commitHoveredButton(S32 x, S32 y) |
1434 | { | 1798 | { |
1435 | BOOL handled = FALSE; | ||
1436 | BOOL has_scroll_arrows = (mMaxScrollPos > 0); | ||
1437 | |||
1438 | if (has_scroll_arrows) | ||
1439 | { | ||
1440 | if (mJumpLeftArrowBtn->getRect().pointInRect(x, y)) | ||
1441 | { | ||
1442 | S32 local_x = x - mJumpLeftArrowBtn->getRect().mLeft; | ||
1443 | S32 local_y = y - mJumpLeftArrowBtn->getRect().mBottom; | ||
1444 | handled = mJumpLeftArrowBtn->handleMouseUp(local_x, local_y, mask); | ||
1445 | } | ||
1446 | if (mJumpRightArrowBtn->getRect().pointInRect(x, y)) | ||
1447 | { | ||
1448 | S32 local_x = x - mJumpRightArrowBtn->getRect().mLeft; | ||
1449 | S32 local_y = y - mJumpRightArrowBtn->getRect().mBottom; | ||
1450 | handled = mJumpRightArrowBtn->handleMouseUp(local_x, local_y, mask); | ||
1451 | } | ||
1452 | if (mLeftArrowBtn->getRect().pointInRect(x, y)) | ||
1453 | { | ||
1454 | S32 local_x = x - mLeftArrowBtn->getRect().mLeft; | ||
1455 | S32 local_y = y - mLeftArrowBtn->getRect().mBottom; | ||
1456 | handled = mLeftArrowBtn->handleMouseUp(local_x, local_y, mask); | ||
1457 | } | ||
1458 | else if (mRightArrowBtn->getRect().pointInRect(x, y)) | ||
1459 | { | ||
1460 | S32 local_x = x - mRightArrowBtn->getRect().mLeft; | ||
1461 | S32 local_y = y - mRightArrowBtn->getRect().mBottom; | ||
1462 | handled = mRightArrowBtn->handleMouseUp(local_x, local_y, mask); | ||
1463 | } | ||
1464 | } | ||
1465 | if (!handled) | ||
1466 | { | ||
1467 | handled = LLPanel::handleMouseUp( x, y, mask ); | ||
1468 | } | ||
1469 | |||
1470 | commitHoveredButton(x, y); | ||
1471 | LLPanel* cur_panel = getCurrentPanel(); | ||
1472 | if (hasMouseCapture()) | 1799 | if (hasMouseCapture()) |
1473 | { | 1800 | { |
1474 | if (cur_panel) | ||
1475 | { | ||
1476 | if (!cur_panel->focusFirstItem(FALSE)) | ||
1477 | { | ||
1478 | // if nothing in the panel gets focus, make sure the new tab does | ||
1479 | // otherwise the last tab might keep focus | ||
1480 | mTabList[getCurrentPanelIndex()]->mButton->setFocus(TRUE); | ||
1481 | } | ||
1482 | } | ||
1483 | gFocusMgr.setMouseCapture(NULL); | ||
1484 | } | ||
1485 | return handled; | ||
1486 | } | ||
1487 | |||
1488 | BOOL LLTabContainer::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect ) | ||
1489 | { | ||
1490 | BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect ); | ||
1491 | if (!handled && mTabList.size() > 0) | ||
1492 | { | ||
1493 | LLTabTuple* firsttuple = mTabList[0]; | ||
1494 | |||
1495 | BOOL has_scroll_arrows = (mMaxScrollPos > 0); | ||
1496 | LLRect clip( | ||
1497 | has_scroll_arrows ? mJumpLeftArrowBtn->getRect().mRight : mJumpLeftArrowBtn->getRect().mLeft, | ||
1498 | firsttuple->mButton->getRect().mTop, | ||
1499 | has_scroll_arrows ? mRightArrowBtn->getRect().mLeft : mRightArrowBtn->getRect().mRight, | ||
1500 | 0 ); | ||
1501 | if( clip.pointInRect( x, y ) ) | ||
1502 | { | ||
1503 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
1504 | { | ||
1505 | LLTabTuple* tuple = *iter; | ||
1506 | tuple->mButton->setVisible( TRUE ); | ||
1507 | S32 local_x = x - tuple->mButton->getRect().mLeft; | ||
1508 | S32 local_y = y - tuple->mButton->getRect().mBottom; | ||
1509 | handled = tuple->mButton->handleToolTip( local_x, local_y, msg, sticky_rect ); | ||
1510 | if( handled ) | ||
1511 | { | ||
1512 | break; | ||
1513 | } | ||
1514 | } | ||
1515 | } | ||
1516 | |||
1517 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | 1801 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) |
1518 | { | 1802 | { |
1519 | LLTabTuple* tuple = *iter; | 1803 | LLTabTuple* tuple = *iter; |
1520 | tuple->mButton->setVisible( FALSE ); | 1804 | tuple->mButton->setVisible( TRUE ); |
1521 | } | 1805 | S32 local_x = x - tuple->mButton->getRect().mLeft; |
1522 | } | 1806 | S32 local_y = y - tuple->mButton->getRect().mBottom; |
1523 | return handled; | 1807 | if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) |
1524 | } | ||
1525 | |||
1526 | BOOL LLTabContainer::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent) | ||
1527 | { | ||
1528 | if (!getEnabled()) return FALSE; | ||
1529 | |||
1530 | if (!gFocusMgr.childHasKeyboardFocus(this)) return FALSE; | ||
1531 | |||
1532 | BOOL handled = FALSE; | ||
1533 | if (key == KEY_LEFT && mask == MASK_ALT) | ||
1534 | { | ||
1535 | selectPrevTab(); | ||
1536 | handled = TRUE; | ||
1537 | } | ||
1538 | else if (key == KEY_RIGHT && mask == MASK_ALT) | ||
1539 | { | ||
1540 | selectNextTab(); | ||
1541 | handled = TRUE; | ||
1542 | } | ||
1543 | |||
1544 | if (handled) | ||
1545 | { | ||
1546 | if (getCurrentPanel()) | ||
1547 | { | ||
1548 | getCurrentPanel()->setFocus(TRUE); | ||
1549 | } | ||
1550 | } | ||
1551 | |||
1552 | if (!gFocusMgr.childHasKeyboardFocus(getCurrentPanel())) | ||
1553 | { | ||
1554 | // if child has focus, but not the current panel, focus | ||
1555 | // is on a button | ||
1556 | switch(key) | ||
1557 | { | ||
1558 | case KEY_UP: | ||
1559 | if (getTabPosition() == BOTTOM && getCurrentPanel()) | ||
1560 | { | ||
1561 | getCurrentPanel()->setFocus(TRUE); | ||
1562 | } | ||
1563 | handled = TRUE; | ||
1564 | break; | ||
1565 | case KEY_DOWN: | ||
1566 | if (getTabPosition() == TOP && getCurrentPanel()) | ||
1567 | { | ||
1568 | getCurrentPanel()->setFocus(TRUE); | ||
1569 | } | ||
1570 | handled = TRUE; | ||
1571 | break; | ||
1572 | case KEY_LEFT: | ||
1573 | selectPrevTab(); | ||
1574 | handled = TRUE; | ||
1575 | break; | ||
1576 | case KEY_RIGHT: | ||
1577 | selectNextTab(); | ||
1578 | handled = TRUE; | ||
1579 | break; | ||
1580 | default: | ||
1581 | break; | ||
1582 | } | ||
1583 | } | ||
1584 | return handled; | ||
1585 | } | ||
1586 | |||
1587 | // virtual | ||
1588 | LLXMLNodePtr LLTabContainer::getXML(bool save_children) const | ||
1589 | { | ||
1590 | LLXMLNodePtr node = LLTabContainerCommon::getXML(); | ||
1591 | |||
1592 | node->createChild("tab_position", TRUE)->setStringValue((mTabPosition == TOP ? "top" : "bottom")); | ||
1593 | |||
1594 | return node; | ||
1595 | } | ||
1596 | |||
1597 | BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType type, void* cargo_data, EAcceptance *accept, LLString &tooltip) | ||
1598 | { | ||
1599 | BOOL has_scroll_arrows = (mMaxScrollPos > 0); | ||
1600 | |||
1601 | if( mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME ) | ||
1602 | { | ||
1603 | |||
1604 | if (has_scroll_arrows) | ||
1605 | { | ||
1606 | if (mJumpLeftArrowBtn->getRect().pointInRect(x, y)) | ||
1607 | { | ||
1608 | S32 local_x = x - mJumpLeftArrowBtn->getRect().mLeft; | ||
1609 | S32 local_y = y - mJumpLeftArrowBtn->getRect().mBottom; | ||
1610 | mJumpLeftArrowBtn->handleHover(local_x, local_y, mask); | ||
1611 | } | ||
1612 | if (mJumpRightArrowBtn->getRect().pointInRect(x, y)) | ||
1613 | { | ||
1614 | S32 local_x = x - mJumpRightArrowBtn->getRect().mLeft; | ||
1615 | S32 local_y = y - mJumpRightArrowBtn->getRect().mBottom; | ||
1616 | mJumpRightArrowBtn->handleHover(local_x, local_y, mask); | ||
1617 | } | ||
1618 | if (mLeftArrowBtn->getRect().pointInRect(x, y)) | ||
1619 | { | ||
1620 | S32 local_x = x - mLeftArrowBtn->getRect().mLeft; | ||
1621 | S32 local_y = y - mLeftArrowBtn->getRect().mBottom; | ||
1622 | mLeftArrowBtn->handleHover(local_x, local_y, mask); | ||
1623 | } | ||
1624 | else if (mRightArrowBtn->getRect().pointInRect(x, y)) | ||
1625 | { | ||
1626 | S32 local_x = x - mRightArrowBtn->getRect().mLeft; | ||
1627 | S32 local_y = y - mRightArrowBtn->getRect().mBottom; | ||
1628 | mRightArrowBtn->handleHover(local_x, local_y, mask); | ||
1629 | } | ||
1630 | } | ||
1631 | |||
1632 | for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) | ||
1633 | { | ||
1634 | LLTabTuple* tuple = *iter; | ||
1635 | tuple->mButton->setVisible( TRUE ); | ||
1636 | S32 local_x = x - tuple->mButton->getRect().mLeft; | ||
1637 | S32 local_y = y - tuple->mButton->getRect().mBottom; | ||
1638 | if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) | ||
1639 | { | 1808 | { |
1640 | tuple->mButton->onCommit(); | 1809 | tuple->mButton->onCommit(); |
1641 | mDragAndDropDelayTimer.stop(); | ||
1642 | } | 1810 | } |
1643 | } | 1811 | } |
1644 | } | 1812 | } |
1645 | |||
1646 | return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); | ||
1647 | } | 1813 | } |
1648 | 1814 | ||
1649 | void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color) | ||
1650 | { | ||
1651 | LLTabTuple* tuple = getTabByPanel(child); | ||
1652 | if( tuple ) | ||
1653 | { | ||
1654 | tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT, color); | ||
1655 | |||
1656 | const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); | ||
1657 | // remove current width from total tab strip width | ||
1658 | mTotalTabWidth -= tuple->mButton->getRect().getWidth(); | ||
1659 | |||
1660 | S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? | ||
1661 | tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : | ||
1662 | 0; | ||
1663 | |||
1664 | tuple->mPadding = image_overlay_width; | ||
1665 | |||
1666 | tuple->mButton->setRightHPad(6); | ||
1667 | tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), | ||
1668 | tuple->mButton->getRect().getHeight()); | ||
1669 | // add back in button width to total tab strip width | ||
1670 | mTotalTabWidth += tuple->mButton->getRect().getWidth(); | ||
1671 | |||
1672 | // tabs have changed size, might need to scroll to see current tab | ||
1673 | updateMaxScrollPos(); | ||
1674 | } | ||
1675 | } | ||