aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/lltabcontainervertical.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llui/lltabcontainervertical.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llui/lltabcontainervertical.cpp')
-rw-r--r--linden/indra/llui/lltabcontainervertical.cpp610
1 files changed, 610 insertions, 0 deletions
diff --git a/linden/indra/llui/lltabcontainervertical.cpp b/linden/indra/llui/lltabcontainervertical.cpp
new file mode 100644
index 0000000..121adf1
--- /dev/null
+++ b/linden/indra/llui/lltabcontainervertical.cpp
@@ -0,0 +1,610 @@
1/**
2 * @file lltabcontainervertical.cpp
3 * @brief LLTabContainerVertical base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28// Fear my script-fu!
29
30#include "linden_common.h"
31
32#include "lltabcontainervertical.h"
33
34#include "llfocusmgr.h"
35#include "llfontgl.h"
36#include "llgl.h"
37
38#include "llbutton.h"
39#include "llrect.h"
40#include "llpanel.h"
41#include "llresmgr.h"
42#include "llkeyboard.h"
43#include "llui.h"
44#include "lltextbox.h"
45#include "llcontrol.h"
46#include "llcriticaldamp.h"
47
48#include "llglheaders.h"
49
50LLTabContainerVertical::LLTabContainerVertical(
51 const LLString& name, const LLRect& rect,
52 void(*close_callback)(void*), void* callback_userdata,
53 U32 tab_width, BOOL bordered)
54 :
55 LLTabContainerCommon(name, rect, LEFT, close_callback, callback_userdata, bordered),
56 mTabWidth(tab_width),
57 mUpArrowBtn(NULL),
58 mDownArrowBtn(NULL)
59{
60 initButtons();
61}
62
63LLTabContainerVertical::LLTabContainerVertical(
64 const LLString& name, const LLString& rect_control,
65 void(*close_callback)(void*), void* callback_userdata,
66 U32 tab_width, BOOL bordered)
67 :
68 LLTabContainerCommon(name, rect_control, LEFT, close_callback, callback_userdata, bordered),
69 mTabWidth(tab_width)
70{
71 initButtons();
72}
73
74// Called from all constructors
75void LLTabContainerVertical::initButtons()
76{
77 // Hack:
78 if (mRect.getHeight() == 0 || mUpArrowBtn)
79 {
80 return; // Don't have a rect yet or already got called
81 }
82
83 LLString out_id;
84 LLString in_id;
85
86 //S32 arrow_fudge = 1; // match new art better
87
88 // Left and right scroll arrows (for when there are too many tabs to show all at once).
89 S32 btn_top = mRect.getHeight();
90 S32 btn_top_lower = mRect.mBottom+TABCNTRV_ARROW_BTN_SIZE;
91
92 LLRect up_arrow_btn_rect;
93 up_arrow_btn_rect.setLeftTopAndSize( mTabWidth/2 , btn_top, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );
94
95 LLRect down_arrow_btn_rect;
96 down_arrow_btn_rect.setLeftTopAndSize( mTabWidth/2 , btn_top_lower, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );
97
98 out_id = "UIImgBtnScrollUpOutUUID";
99 in_id = "UIImgBtnScrollUpInUUID";
100 mUpArrowBtn = new LLButton(
101 "Up Arrow", up_arrow_btn_rect,
102 out_id, in_id, "",
103 &onPrevBtn, this, NULL );
104 mUpArrowBtn->setHeldDownCallback(onPrevBtnHeld);
105 mUpArrowBtn->setSaveToXML(false);
106 mUpArrowBtn->setFollowsTop();
107 mUpArrowBtn->setFollowsLeft();
108 mUpArrowBtn->setTabStop(FALSE);
109 addChild(mUpArrowBtn);
110
111 out_id = "UIImgBtnScrollDownOutUUID";
112 in_id = "UIImgBtnScrollDownInUUID";
113 mDownArrowBtn = new LLButton(
114 "Down Arrow", down_arrow_btn_rect,
115 out_id, in_id, "",
116 &onNextBtn, this, NULL );
117 mDownArrowBtn->setHeldDownCallback(onNextBtnHeld);
118 mDownArrowBtn->setSaveToXML(false);
119 mDownArrowBtn->setFollowsBottom();
120 mDownArrowBtn->setFollowsLeft();
121 mDownArrowBtn->setTabStop(FALSE);
122 addChild(mDownArrowBtn);
123
124 // set default tab group to be panel contents
125 mDefaultTabGroup = 1;
126}
127
128LLTabContainerVertical::~LLTabContainerVertical()
129{ }
130
131void LLTabContainerVertical::addTabPanel(LLPanel* child, const LLString& label,
132 BOOL select,
133 void (*on_tab_clicked)(void*, bool), void* userdata,
134 S32 indent,
135 BOOL placeholder, eInsertionPoint insertion_point)
136{
137 if (child->getParent() == this)
138 {
139 // already a child of mine
140 return;
141 }
142
143 const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF );
144
145 // Store the original label for possible xml export.
146 child->setLabel(label);
147 // Replace long label with truncated version (e.g., "FooBa...")
148 LLString trimmed_label = label;
149 LLString::trim(trimmed_label);
150
151 // Tab panel
152 S32 tab_panel_top;
153 S32 tab_panel_bottom;
154 tab_panel_top = mRect.getHeight()
155 - mTopBorderHeight
156 - (BTN_HEIGHT - TABCNTRV_BUTTON_PANEL_OVERLAP);
157 tab_panel_bottom = LLPANEL_BORDER_WIDTH;
158
159 LLRect tab_panel_rect(
160 mTabWidth + (LLPANEL_BORDER_WIDTH * 2) + TABCNTRV_PAD,
161 mRect.getHeight() - LLPANEL_BORDER_WIDTH,
162 mRect.getWidth() - LLPANEL_BORDER_WIDTH,
163 LLPANEL_BORDER_WIDTH);
164
165 child->setFollowsAll();
166 child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom);
167 child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
168 child->setBackgroundVisible( FALSE ); // No need to overdraw
169
170 child->setVisible( FALSE ); // Will be made visible when selected
171
172 // Tab button
173 LLRect btn_rect;
174 btn_rect.setLeftTopAndSize(
175 TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor
176 (mRect.getHeight() - mTopBorderHeight - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * mTabList.size()),
177 mTabWidth,
178 BTN_HEIGHT);
179
180 if (!placeholder)
181 {
182 LLButton *btn = new LLButton("vert tab button",
183 btn_rect,
184 "tab_left.tga",
185 "tab_left_selected.tga",
186 "",
187 &LLTabContainerVertical::onTabBtn, NULL,
188 font,
189 trimmed_label, trimmed_label);
190 btn->setSaveToXML(false);
191 btn->setFixedBorder(16, 16);
192 btn->setScaleImage(TRUE);
193 btn->setHAlign(LLFontGL::LEFT);
194 btn->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
195 btn->setTabStop(FALSE);
196 if (indent)
197 {
198 btn->setLeftHPad(indent);
199 }
200
201 LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata );
202 insertTuple( tuple, insertion_point );
203
204 btn->setCallbackUserData( tuple );
205 addChild( btn, 0 );
206 addChild(child, 1);
207
208 if( select )
209 {
210 selectTab( mTabList.size()-1 );
211 }
212 }
213 else
214 {
215 btn_rect.translate(0, -LLBUTTON_V_PAD-2);
216 LLString box_label = trimmed_label;
217 LLTextBox* text = new LLTextBox(box_label, btn_rect, box_label, font);
218 text->setSaveToXML(false);
219 addChild( text, 0 );
220
221 LLButton* btn = new LLButton("", LLRect(0,0,0,0));
222 btn->setSaveToXML(false);
223 addChild(btn, 0);
224 addChild(child, 1);
225
226 LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata, text );
227 insertTuple( tuple, insertion_point );
228 }
229
230 updateMaxScrollPos();
231}
232
233void LLTabContainerVertical::removeTabPanel(LLPanel* child)
234{
235 LLTabContainerCommon::removeTabPanel(child);
236
237 // Fix-up button sizes
238 S32 tab_count = 0;
239 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
240 {
241 LLTabTuple* tuple = *iter;
242 LLRect rect;
243 rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2, // JC - Fudge factor
244 (mRect.getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * (tab_count)),
245 mTabWidth,
246 BTN_HEIGHT);
247 if (tuple->mPlaceholderText)
248 {
249 tuple->mPlaceholderText->setRect(rect);
250 }
251 else
252 {
253 tuple->mButton->setRect(rect);
254 }
255 tab_count++;
256 }
257}
258
259void LLTabContainerVertical::updateMaxScrollPos()
260{
261 S32 tab_total_height = (BTN_HEIGHT + TABCNTRV_PAD) * mTabList.size();
262 S32 available_height = mRect.getHeight() - mTopBorderHeight;
263 if( tab_total_height > available_height )
264 {
265 S32 available_height_with_arrows = mRect.getHeight() - 2*(TABCNTRV_ARROW_BTN_SIZE + 3*TABCNTRV_PAD);
266 S32 additional_needed = tab_total_height - available_height_with_arrows;
267 mMaxScrollPos = S32( ceil(additional_needed / float(BTN_HEIGHT) ) );
268 }
269 else
270 {
271 mMaxScrollPos = 0;
272 mScrollPos = 0;
273 }
274 if (mScrollPos > mMaxScrollPos)
275 {
276 mScrollPos = mMaxScrollPos;
277 }
278}
279
280void LLTabContainerVertical::commitHoveredButton(S32 x, S32 y)
281{
282 if (gFocusMgr.getMouseCapture() == this)
283 {
284 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
285 {
286 LLTabTuple* tuple = *iter;
287 tuple->mButton->setVisible( TRUE );
288 S32 local_x = x - tuple->mButton->getRect().mLeft;
289 S32 local_y = y - tuple->mButton->getRect().mBottom;
290 if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible())
291 {
292 tuple->mButton->onCommit();
293 }
294 }
295 }
296}
297
298BOOL LLTabContainerVertical::selectTab(S32 which)
299{
300 if (which >= (S32)mTabList.size()) return FALSE;
301 if (which < 0) return FALSE;
302
303 //if( gFocusMgr.childHasKeyboardFocus( this ) )
304 //{
305 // gFocusMgr.setKeyboardFocus( NULL, NULL );
306 //}
307
308 LLTabTuple* selected_tuple = mTabList[which];
309 if (!selected_tuple)
310 {
311 return FALSE;
312 }
313
314 BOOL is_visible = FALSE;
315 if (which != mCurrentTabIdx)
316 {
317 mCurrentTabIdx = which;
318
319 S32 i = 0;
320 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
321 {
322 LLTabTuple* tuple = *iter;
323 BOOL is_selected = ( tuple == selected_tuple );
324 tuple->mTabPanel->setVisible( is_selected );
325// tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here.
326 tuple->mButton->setToggleState( is_selected );
327 // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs
328 tuple->mButton->setTabStop( is_selected );
329
330 if( is_selected )
331 {
332 // Make sure tab is within scroll
333 S32 num_visible = mTabList.size() - mMaxScrollPos;
334 if( i >= mScrollPos && i <= mScrollPos + num_visible)
335 {
336 mCurrentTabIdx = which;
337 is_visible = TRUE;
338 }
339 else
340 {
341 is_visible = FALSE;
342 }
343 }
344 i++;
345 }
346 if( selected_tuple->mOnChangeCallback )
347 {
348 selected_tuple->mOnChangeCallback( selected_tuple->mUserData, false );
349 }
350 }
351 if(mCurrentTabIdx >= 0)
352 {
353 LLTabTuple* tuple = mTabList[mCurrentTabIdx];
354 tuple->mTabPanel->setVisible( TRUE );
355 tuple->mButton->setToggleState( TRUE );
356 }
357 return is_visible;
358}
359
360
361
362void LLTabContainerVertical::draw()
363{
364 S32 target_pixel_scroll = mScrollPos * (BTN_HEIGHT + TABCNTRV_PAD);
365
366 mScrollPosPixels = (S32)lerp((F32)mScrollPosPixels, (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f));
367 if( getVisible() )
368 {
369 BOOL has_scroll_arrows = (mMaxScrollPos > 0) || (mScrollPosPixels > 0);
370 mUpArrowBtn->setVisible( has_scroll_arrows );
371 mDownArrowBtn->setVisible( has_scroll_arrows );
372
373 // Set the topmost position of the tab buttons.
374 S32 top = mRect.getHeight() - mTopBorderHeight - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? TABCNTRV_ARROW_BTN_SIZE : 0);
375 top += mScrollPosPixels;
376
377 // Hide all the buttons
378 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
379 {
380 LLTabTuple* tuple = *iter;
381 tuple->mButton->setVisible( FALSE );
382 }
383
384 LLPanel::draw();
385
386 // Show all the buttons
387 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
388 {
389 LLTabTuple* tuple = *iter;
390 tuple->mButton->setVisible( TRUE );
391 }
392
393 // Draw some of the buttons...
394
395 LLGLEnable scissor_test(has_scroll_arrows ? GL_SCISSOR_TEST : GL_FALSE);
396
397 if( has_scroll_arrows )
398 {
399 // ...but clip them.
400 S32 x1 = mRect.mLeft;
401 S32 y1 = mDownArrowBtn->getRect().mTop + 3*TABCNTRV_PAD;
402 S32 x2 = mRect.mRight;
403 S32 y2 = mUpArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD;
404 LLUI::setScissorRegionLocal(LLRect(x1, y2, x2, y1));
405 }
406
407 //S32 max_scroll_visible = mTabList.size() - mMaxScrollPos + mScrollPos;
408 S32 idx = 0;
409 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
410 {
411 LLTabTuple* tuple = *iter;
412 tuple->mButton->translate( 0 , top - tuple->mButton->getRect().mTop);
413 top -= BTN_HEIGHT + TABCNTRV_PAD;
414
415 LLUI::pushMatrix();
416 {
417 LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f);
418 tuple->mButton->draw();
419 }
420 LLUI::popMatrix();
421
422 idx++;
423 }
424
425 if( has_scroll_arrows )
426 {
427 // Redraw the arrows so that they appears on top.
428 glPushMatrix();
429 glTranslatef((F32)mUpArrowBtn->getRect().mLeft, (F32)mUpArrowBtn->getRect().mBottom, 0.f);
430 mUpArrowBtn->draw();
431 glPopMatrix();
432
433 glPushMatrix();
434 glTranslatef((F32)mDownArrowBtn->getRect().mLeft, (F32)mDownArrowBtn->getRect().mBottom, 0.f);
435 mDownArrowBtn->draw();
436 glPopMatrix();
437 }
438 }
439}
440
441BOOL LLTabContainerVertical::handleMouseDown( S32 x, S32 y, MASK mask )
442{
443 BOOL handled = FALSE;
444 BOOL has_scroll_arrows = (mMaxScrollPos > 0);
445
446 if (has_scroll_arrows)
447 {
448 if (mUpArrowBtn->getRect().pointInRect(x, y))
449 {
450 S32 local_x = x - mUpArrowBtn->getRect().mLeft;
451 S32 local_y = y - mUpArrowBtn->getRect().mBottom;
452 handled = mUpArrowBtn->handleMouseDown(local_x, local_y, mask);
453 }
454 else if (mDownArrowBtn->getRect().pointInRect(x, y))
455 {
456 S32 local_x = x - mDownArrowBtn->getRect().mLeft;
457 S32 local_y = y - mDownArrowBtn->getRect().mBottom;
458 handled = mDownArrowBtn->handleMouseDown(local_x, local_y, mask);
459 }
460 }
461 if (!handled)
462 {
463 handled = LLPanel::handleMouseDown( x, y, mask );
464 }
465
466 if (mTabList.size() > 0)
467 {
468 LLTabTuple* firsttuple = mTabList[0];
469 LLRect tab_rect(firsttuple->mButton->getRect().mLeft,
470 has_scroll_arrows ? mUpArrowBtn->getRect().mBottom - TABCNTRV_PAD : mUpArrowBtn->getRect().mTop,
471 firsttuple->mButton->getRect().mRight,
472 has_scroll_arrows ? mDownArrowBtn->getRect().mTop + TABCNTRV_PAD : mDownArrowBtn->getRect().mBottom );
473 if( tab_rect.pointInRect( x, y ) )
474 {
475 LLButton* tab_button = mTabList[getCurrentPanelIndex()]->mButton;
476 gFocusMgr.setMouseCapture(this, NULL);
477 gFocusMgr.setKeyboardFocus(tab_button, NULL);
478 }
479 }
480 return handled;
481}
482
483BOOL LLTabContainerVertical::handleHover( S32 x, S32 y, MASK mask )
484{
485 BOOL handled = FALSE;
486 BOOL has_scroll_arrows = (mMaxScrollPos > 0);
487
488 if (has_scroll_arrows)
489 {
490 if (mUpArrowBtn->getRect().pointInRect(x, y))
491 {
492 S32 local_x = x - mUpArrowBtn->getRect().mLeft;
493 S32 local_y = y - mUpArrowBtn->getRect().mBottom;
494 handled = mUpArrowBtn->handleHover(local_x, local_y, mask);
495 }
496 else if (mDownArrowBtn->getRect().pointInRect(x, y))
497 {
498 S32 local_x = x - mDownArrowBtn->getRect().mLeft;
499 S32 local_y = y - mDownArrowBtn->getRect().mBottom;
500 handled = mDownArrowBtn->handleHover(local_x, local_y, mask);
501 }
502 }
503 if (!handled)
504 {
505 handled = LLPanel::handleHover(x, y, mask);
506 }
507
508 commitHoveredButton(x, y);
509 return handled;
510}
511
512BOOL LLTabContainerVertical::handleMouseUp( S32 x, S32 y, MASK mask )
513{
514 BOOL handled = FALSE;
515 BOOL has_scroll_arrows = (mMaxScrollPos > 0);
516
517 if (has_scroll_arrows)
518 {
519 if (mUpArrowBtn->getRect().pointInRect(x, y))
520 {
521 S32 local_x = x - mUpArrowBtn->getRect().mLeft;
522 S32 local_y = y - mUpArrowBtn->getRect().mBottom;
523 handled = mUpArrowBtn->handleMouseUp(local_x, local_y, mask);
524 }
525 else if (mDownArrowBtn->getRect().pointInRect(x, y))
526 {
527 S32 local_x = x - mDownArrowBtn->getRect().mLeft;
528 S32 local_y = y - mDownArrowBtn->getRect().mBottom;
529 handled = mDownArrowBtn->handleMouseUp(local_x, local_y, mask);
530 }
531 }
532 if (!handled)
533 {
534 handled = LLPanel::handleMouseUp( x, y, mask );
535 }
536
537 commitHoveredButton(x, y);
538 LLPanel* cur_panel = getCurrentPanel();
539 if (gFocusMgr.getMouseCapture() == this)
540 {
541 if (cur_panel)
542 {
543 if (!cur_panel->focusFirstItem(FALSE))
544 {
545 mTabList[getCurrentPanelIndex()]->mButton->setFocus(TRUE);
546 }
547 }
548 gFocusMgr.setMouseCapture(NULL, NULL);
549 }
550
551 return handled;
552}
553
554BOOL LLTabContainerVertical::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
555{
556 BOOL handled = FALSE;
557 if (getEnabled())
558 {
559 if (key == '[' && mask == MASK_CONTROL)
560 {
561 selectPrevTab();
562 handled = TRUE;
563 }
564 else if (key == ']' && mask == MASK_CONTROL)
565 {
566 selectNextTab();
567 handled = TRUE;
568 }
569
570 // focus is on button
571 if (!handled && !gFocusMgr.childHasKeyboardFocus(getCurrentPanel()))
572 {
573 switch(key)
574 {
575 case KEY_UP:
576 selectPrevTab();
577 handled = TRUE;
578 break;
579 case KEY_DOWN:
580 selectNextTab();
581 handled = TRUE;
582 break;
583 case KEY_LEFT:
584 handled = TRUE;
585 break;
586 case KEY_RIGHT:
587 if (getTabPosition() == LEFT && getCurrentPanel())
588 {
589 getCurrentPanel()->setFocus(TRUE);
590 }
591 handled = TRUE;
592 break;
593 default:
594 break;
595 }
596 }
597 }
598 return handled;
599}
600
601// virtual
602LLXMLNodePtr LLTabContainerVertical::getXML(bool save_children) const
603{
604 LLXMLNodePtr node = LLTabContainerCommon::getXML();
605
606 // TomY TODO Is this redundant or will it be used later?
607 node->createChild("tab_position", TRUE)->setStringValue("left");
608
609 return node;
610}