PageRenderTime 601ms CodeModel.GetById 235ms app.highlight 125ms RepoModel.GetById 237ms app.codeStats 0ms

/indra/newview/llsplitbutton.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 266 lines | 175 code | 55 blank | 36 comment | 17 complexity | a8769c22ed907282c4748dc6f4c30046 MD5 | raw file
  1/** 
  2 * @file llsplitbutton.cpp
  3 * @brief LLSplitButton base class
  4 *
  5 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27// A control that consolidates several buttons as options
 28
 29#include "llviewerprecompiledheaders.h"
 30
 31#include "llsplitbutton.h"
 32
 33#include "llinitparam.h"
 34#include "llpanel.h"
 35#include "llfocusmgr.h"
 36#include "llviewerwindow.h"
 37#include "llrootview.h"
 38
 39
 40S32 BUTTON_PAD = 2; //pad between buttons on an items panel
 41
 42
 43static LLDefaultChildRegistry::Register<LLSplitButton> split_button("split_button");
 44
 45void LLSplitButton::ArrowPositionValues::declareValues()
 46{
 47	declare("left", LEFT);
 48	declare("right", RIGHT);
 49}
 50
 51LLSplitButton::ItemParams::ItemParams()
 52{
 53}
 54
 55LLSplitButton::Params::Params()
 56:	arrow_position("arrow_position", LEFT),
 57	items("item"),
 58	arrow_button("arrow_button"),
 59	items_panel("items_panel")
 60{
 61}
 62
 63
 64void LLSplitButton::onFocusLost()
 65{
 66	hideButtons();
 67	LLUICtrl::onFocusLost();
 68}
 69
 70void LLSplitButton::setFocus(BOOL b)
 71{
 72	LLUICtrl::setFocus(b);
 73
 74	if (b)
 75	{
 76		if (mItemsPanel && mItemsPanel->getVisible())
 77		{
 78			mItemsPanel->setFocus(TRUE);
 79		}
 80	}
 81}
 82
 83void LLSplitButton::setEnabled(BOOL enabled)
 84{
 85	LLView::setEnabled(enabled);
 86	mArrowBtn->setEnabled(enabled);
 87}
 88
 89
 90void LLSplitButton::onArrowBtnDown()
 91{
 92	if (!mItemsPanel->getVisible())
 93	{
 94		showButtons();
 95
 96		setFocus(TRUE);
 97
 98		if (mArrowBtn->hasMouseCapture() || mShownItem->hasMouseCapture())
 99		{
100			gFocusMgr.setMouseCapture(this);
101		}
102	}
103	else
104	{
105		hideButtons();
106	}
107}
108
109void LLSplitButton::onHeldDownShownButton()
110{
111	if (!mItemsPanel->getVisible()) onArrowBtnDown();
112}
113
114void LLSplitButton::onItemSelected(LLUICtrl* ctrl)
115{
116	if (!ctrl) return;
117
118	hideButtons();
119
120	// call the callback if it exists
121	if(!mSelectionCallback.empty())
122	{
123		mSelectionCallback(this, ctrl->getName());
124	}
125
126	gFocusMgr.setKeyboardFocus(NULL);
127}
128
129BOOL LLSplitButton::handleMouseUp(S32 x, S32 y, MASK mask)
130{
131	gFocusMgr.setMouseCapture(NULL);
132
133	if (mShownItem->parentPointInView(x, y))
134	{
135		onItemSelected(mShownItem);
136		return TRUE;
137	}
138
139	for (std::list<LLButton*>::const_iterator it = mHidenItems.begin(); it != mHidenItems.end(); ++it)
140	{
141		LLButton* item = *it;
142
143		S32 panel_x = 0;
144		S32 panel_y = 0;
145		localPointToOtherView(x, y, &panel_x, &panel_y, mItemsPanel);
146
147		if (item->parentPointInView(panel_x, panel_y))
148		{
149			onItemSelected(item);
150			return TRUE;
151		}
152	}
153	return TRUE;
154}
155
156void LLSplitButton::showButtons()
157{
158	mItemsPanel->setOrigin(0, getRect().getHeight());
159
160	// register ourselves as a "top" control
161	// effectively putting us into a special draw layer
162	gViewerWindow->addPopup(this);
163
164	mItemsPanel->setFocus(TRUE);
165
166	//push arrow button down and show the item buttons
167	mArrowBtn->setToggleState(TRUE);
168	mItemsPanel->setVisible(TRUE);
169
170	setUseBoundingRect(TRUE);
171}
172
173void LLSplitButton::hideButtons()
174{
175	mItemsPanel->setVisible(FALSE);
176	mArrowBtn->setToggleState(FALSE);
177
178	setUseBoundingRect(FALSE);
179	gViewerWindow->removePopup(this);
180}
181
182
183// protected/private
184
185LLSplitButton::LLSplitButton(const LLSplitButton::Params& p)
186:	LLUICtrl(p),
187	mArrowBtn(NULL),
188	mShownItem(NULL),
189	mItemsPanel(NULL),
190	mArrowPosition(p.arrow_position)
191{
192	LLRect rc(p.rect);
193
194	LLButton::Params arrow_params = p.arrow_button;
195	S32 arrow_width = p.arrow_button.rect.width;
196
197	//Default arrow rect values for LEFT arrow position
198	S32 arrow_left = 0;
199	S32 arrow_right = arrow_width;
200	S32 btn_left = arrow_width;
201	S32 btn_right = rc.getWidth();
202
203	if (mArrowPosition == RIGHT)
204	{
205		arrow_left = rc.getWidth()- arrow_width;
206		arrow_right = rc.getWidth();
207		btn_left = 0;
208		btn_right = arrow_left;
209	}
210
211	arrow_params.rect(LLRect(arrow_left, rc.getHeight(), arrow_right, 0));
212	arrow_params.label("");
213	arrow_params.mouse_down_callback.function(boost::bind(&LLSplitButton::onArrowBtnDown, this));
214	mArrowBtn = LLUICtrlFactory::create<LLButton>(arrow_params);
215	addChild(mArrowBtn);
216
217	//a panel for hidden item buttons
218	LLPanel::Params panel_params = p.items_panel;
219	mItemsPanel= prepareItemsPanel(panel_params, p.items.numValidElements());
220	addChild(mItemsPanel);
221
222
223	LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin();
224
225	//processing shown item button
226	mShownItem = prepareItemButton(*it);
227	mShownItem->setHeldDownCallback(boost::bind(&LLSplitButton::onHeldDownShownButton, this));
228	mShownItem->setMouseUpCallback(boost::bind(&LLSplitButton::onItemSelected, this, _1));
229	mShownItem->setRect(LLRect(btn_left, rc.getHeight(), btn_right, 0));
230	addChild(mShownItem);
231
232	//processing hidden item buttons
233	S32 item_top = mItemsPanel->getRect().getHeight();
234	for (++it; it != p.items.end(); ++it)
235	{
236		LLButton* hidden_button = prepareItemButton(*it);
237		hidden_button->setRect(LLRect(btn_left, item_top, btn_right, item_top - rc.getHeight()));
238		hidden_button->setMouseDownCallback(boost::bind(&LLSplitButton::onItemSelected, this, _1));
239		mHidenItems.push_back(hidden_button);
240		mItemsPanel->addChild(hidden_button);
241
242		//calculate next button's top
243		item_top -= (rc.getHeight() + BUTTON_PAD);
244	}
245
246	setTopLostCallback(boost::bind(&LLSplitButton::hideButtons, this));
247}
248
249
250LLButton* LLSplitButton::prepareItemButton(LLButton::Params params)
251{
252	params.label("");
253	params.is_toggle(false);
254	return LLUICtrlFactory::create<LLButton>(params); 
255}
256
257LLPanel* LLSplitButton::prepareItemsPanel(LLPanel::Params params, S32 items_count)
258{
259	S32 num_hiden_btns = items_count - 1;
260	S32 panel_height = num_hiden_btns * (getRect().getHeight() + BUTTON_PAD);
261	params.visible(false);
262	params.rect.width(getRect().getWidth());
263	params.rect.height(panel_height);
264	return LLUICtrlFactory::create<LLPanel>(params);
265}
266