Modernize llradiogroup, allows v3-style attributes: value, label for radio_item; allow_deselect for radio_group.

LLRadioCtrl moves into llradiogroup.cpp
This commit is contained in:
Inusaito Sayori
2014-08-19 19:41:00 -04:00
parent 2f4afe5b68
commit 435ab2ce77
4 changed files with 127 additions and 89 deletions

View File

@@ -46,16 +46,36 @@
static LLRegisterWidget<LLRadioGroup> r("radio_group");
/*
* A checkbox control with use_radio_style == true.
*/
class LLRadioCtrl : public LLCheckBoxCtrl
{
public:
LLRadioCtrl(const std::string& name, const LLRect& rect, const std::string& label, const std::string& value = "", const LLFontGL* font = NULL, commit_callback_t commit_callback = NULL);
/*virtual*/ ~LLRadioCtrl();
virtual LLXMLNodePtr getXML(bool save_children = true) const;
/*virtual*/ void setValue(const LLSD& value);
LLSD getPayload() { return mPayload; }
protected:
friend class LLUICtrlFactory;
LLSD mPayload; // stores data that this item represents in the radio group
};
LLRadioGroup::LLRadioGroup(const std::string& name, const LLRect& rect,
S32 initial_index, commit_callback_t commit_callback,
BOOL border) :
bool border, bool allow_deselect) :
LLUICtrl(name, rect, TRUE, commit_callback, FOLLOWS_LEFT | FOLLOWS_TOP),
mSelectedIndex(initial_index)
mSelectedIndex(initial_index),
mAllowDeselect(allow_deselect)
{
init(border);
}
void LLRadioGroup::init(BOOL border)
void LLRadioGroup::init(bool border)
{
if (border)
{
@@ -67,12 +87,19 @@ void LLRadioGroup::init(BOOL border)
}
LLRadioGroup::~LLRadioGroup()
{
}
// virtual
BOOL LLRadioGroup::postBuild()
{
if (!mRadioButtons.empty())
{
mRadioButtons[0]->setTabStop(true);
}
return TRUE;
}
// virtual
void LLRadioGroup::setEnabled(BOOL enabled)
@@ -133,16 +160,39 @@ void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled)
BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)
{
if (index < 0 || index >= (S32)mRadioButtons.size())
if ((S32)mRadioButtons.size() <= index )
{
return FALSE;
}
if (mSelectedIndex >= 0)
{
LLRadioCtrl* old_radio_item = mRadioButtons[mSelectedIndex];
old_radio_item->setTabStop(false);
old_radio_item->setValue( FALSE );
}
else
{
mRadioButtons[0]->setTabStop(false);
}
mSelectedIndex = index;
if (mSelectedIndex >= 0)
{
LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex];
radio_item->setTabStop(true);
radio_item->setValue( TRUE );
if (hasFocus())
{
radio_item->focusFirstItem(FALSE, FALSE);
}
}
if (!from_event)
{
setControlValue(getSelectedIndex());
setControlValue(getValue());
}
return TRUE;
@@ -207,41 +257,23 @@ BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask)
return handled;
}
void LLRadioGroup::draw()
BOOL LLRadioGroup::handleMouseDown(S32 x, S32 y, MASK mask)
{
S32 current_button = 0;
BOOL take_focus = FALSE;
if (gFocusMgr.childHasKeyboardFocus(this))
// grab focus preemptively, before child button takes mousecapture
//
if (hasTabStop())
{
take_focus = TRUE;
focusFirstItem(FALSE, FALSE);
}
for (button_list_t::iterator iter = mRadioButtons.begin();
iter != mRadioButtons.end(); ++iter)
{
LLRadioCtrl* radio = *iter;
BOOL selected = (current_button == mSelectedIndex);
radio->setValue( selected );
if (take_focus && selected && !gFocusMgr.childHasKeyboardFocus(radio))
{
// don't flash keyboard focus when navigating via keyboard
BOOL DONT_FLASH = FALSE;
radio->focusFirstItem(FALSE, DONT_FLASH);
}
current_button++;
}
LLView::draw();
return LLUICtrl::handleMouseDown(x, y, mask);
}
// When adding a button, we need to ensure that the radio
// group gets a message when the button is clicked.
LLRadioCtrl* LLRadioGroup::addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font )
LLRadioCtrl* LLRadioGroup::addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font, const std::string& payload)
{
// Highlight will get fixed in draw method above
LLRadioCtrl* radio = new LLRadioCtrl(name, rect, label, font, boost::bind(&LLRadioGroup::onClickButton, this, _1));
LLRadioCtrl* radio = new LLRadioCtrl(name, rect, label, payload, font, boost::bind(&LLRadioGroup::onClickButton, this, _1));
addChild(radio);
mRadioButtons.push_back(radio);
return radio;
@@ -252,7 +284,7 @@ LLRadioCtrl* LLRadioGroup::addRadioButton(const std::string& name, const std::st
void LLRadioGroup::onClickButton(LLUICtrl* ctrl)
{
// llinfos << "LLRadioGroup::onClickButton" << llendl;
// LL_INFOS() << "LLRadioGroup::onClickButton" << LL_ENDL;
LLRadioCtrl* clicked_radio = dynamic_cast<LLRadioCtrl*>(ctrl);
if (!clicked_radio)
return;
@@ -263,9 +295,15 @@ void LLRadioGroup::onClickButton(LLUICtrl* ctrl)
LLRadioCtrl* radio = *iter;
if (radio == clicked_radio)
{
// llinfos << "clicked button " << counter << llendl;
setSelectedIndex(index);
setControlValue(index);
if (index == mSelectedIndex && mAllowDeselect)
{
// don't select anything
setSelectedIndex(-1);
}
else
{
setSelectedIndex(index);
}
// BUG: Calls click callback even if button didn't actually change
onCommit();
@@ -281,13 +319,12 @@ void LLRadioGroup::onClickButton(LLUICtrl* ctrl)
void LLRadioGroup::setValue( const LLSD& value )
{
std::string value_name = value.asString();
int idx = 0;
for (button_list_t::const_iterator iter = mRadioButtons.begin();
iter != mRadioButtons.end(); ++iter)
{
LLRadioCtrl* radio = *iter;
if (radio->getName() == value_name)
if (radio->getPayload().asString() == value.asString())
{
setSelectedIndex(idx);
idx = -1;
@@ -304,8 +341,7 @@ void LLRadioGroup::setValue( const LLSD& value )
}
else
{
llwarns << "LLRadioGroup::setValue: radio_item with name=\"" << value_name << "\" not found, radio_group values are set by radio_item name not value. Falling back on LLUICtrl::setValue." << llendl;
LLUICtrl::setValue(value);
setSelectedIndex(-1, TRUE);
}
}
}
@@ -317,7 +353,7 @@ LLSD LLRadioGroup::getValue() const
for (button_list_t::const_iterator iter = mRadioButtons.begin();
iter != mRadioButtons.end(); ++iter)
{
if (idx == index) return LLSD((*iter)->getName());
if (idx == index) return LLSD((*iter)->getPayload());
++idx;
}
return LLSD();
@@ -333,6 +369,7 @@ LLXMLNodePtr LLRadioGroup::getXML(bool save_children) const
// Attributes
node->createChild("draw_border", TRUE)->setBoolValue(mHasBorder);
node->createChild("allow_deselect", TRUE)->setBoolValue(mAllowDeselect);
// Contents
@@ -355,17 +392,21 @@ LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory
U32 initial_value = 0;
node->getAttributeU32("initial_value", initial_value);
BOOL draw_border = TRUE;
node->getAttributeBOOL("draw_border", draw_border);
bool draw_border = true;
node->getAttribute_bool("draw_border", draw_border);
bool allow_deselect = false;
node->getAttribute_bool("allow_deselect", allow_deselect);
LLRect rect;
createRect(node, rect, parent, LLRect());
LLRadioGroup* radio_group = new LLRadioGroup("radio_group",
LLRadioGroup* radio_group = new LLRadioGroup("radio_group",
rect,
initial_value,
NULL,
draw_border);
draw_border,
allow_deselect);
const std::string& contents = node->getValue();
@@ -406,7 +447,13 @@ LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory
createRect(child, item_rect, radio_group, rect);
std::string item_label = child->getTextContents();
LLRadioCtrl* radio = radio_group->addRadioButton("radio", item_label, item_rect, font);
node->getAttributeString("label", item_label);
std::string item_name("radio");
node->getAttributeString("name", item_name);
std::string payload(item_name); // Support old-style name as payload
node->getAttributeString("value", payload);
node->getAttributeString("initial_value", payload); // Synonym
LLRadioCtrl* radio = radio_group->addRadioButton(item_name, item_label, item_rect, font, payload);
radio->initFromXML(child, radio_group);
}
@@ -432,11 +479,10 @@ LLUUID LLRadioGroup::getCurrentID() const
BOOL LLRadioGroup::setSelectedByValue(const LLSD& value, BOOL selected)
{
S32 idx = 0;
std::string value_string = value.asString();
for (button_list_t::const_iterator iter = mRadioButtons.begin();
iter != mRadioButtons.end(); ++iter)
{
if((*iter)->getName() == value_string)
if((*iter)->getPayload().asString() == value.asString())
{
setSelectedIndex(idx);
return TRUE;
@@ -455,11 +501,10 @@ LLSD LLRadioGroup::getSelectedValue()
BOOL LLRadioGroup::isSelected(const LLSD& value) const
{
S32 idx = 0;
std::string value_string = value.asString();
for (button_list_t::const_iterator iter = mRadioButtons.begin();
iter != mRadioButtons.end(); ++iter)
{
if((*iter)->getName() == value_string)
if((*iter)->getPayload().asString() == value.asString())
{
if (idx == mSelectedIndex)
{
@@ -481,6 +526,17 @@ BOOL LLRadioGroup::operateOnAll(EOperation op)
return FALSE;
}
LLRadioCtrl::LLRadioCtrl(const std::string& name, const LLRect& rect, const std::string& label, const std::string& value, const LLFontGL* font, commit_callback_t commit_callback)
: LLCheckBoxCtrl(name, rect, label, font, commit_callback, FALSE, RADIO_STYLE),
mPayload(value)
{
setTabStop(FALSE);
// use name as default "Value" for backwards compatibility
if (value.empty())
{
mPayload = name;
}
}
LLRadioCtrl::~LLRadioCtrl()
{
@@ -499,7 +555,7 @@ LLXMLNodePtr LLRadioCtrl::getXML(bool save_children) const
node->setName(LL_RADIO_ITEM_TAG);
node->setStringValue(getLabel());
node->createChild("value", TRUE)->setStringValue(mPayload);
return node;
}

View File

@@ -37,26 +37,6 @@
#include "llcheckboxctrl.h"
#include "llctrlselectioninterface.h"
/*
* A checkbox control with use_radio_style == true.
*/
class LLRadioCtrl : public LLCheckBoxCtrl
{
public:
LLRadioCtrl(const std::string& name, const LLRect& rect, const std::string& label, const LLFontGL* font = NULL,
commit_callback_t commit_callback = NULL) :
LLCheckBoxCtrl(name, rect, label, font, commit_callback, FALSE, RADIO_STYLE)
{
setTabStop(FALSE);
}
/*virtual*/ ~LLRadioCtrl();
virtual LLXMLNodePtr getXML(bool save_children = true) const;
/*virtual*/ void setValue(const LLSD& value);
};
/*
* An invisible view containing multiple mutually exclusive toggling
* buttons (usually radio buttons). Automatically handles the mutex
@@ -66,25 +46,32 @@ class LLRadioGroup
: public LLUICtrl, public LLCtrlSelectionInterface
{
public:
// Radio group constructor. Doesn't rely on
// needing a control
// Radio group constructor. Doesn't rely on needing a control
LLRadioGroup(const std::string& name, const LLRect& rect,
S32 initial_index,
commit_callback_t commit_callback,
BOOL border = TRUE);
bool border = true, bool allow_deselect = false);
protected:
friend class LLUICtrlFactory;
public:
virtual ~LLRadioGroup();
virtual BOOL postBuild();
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleKeyHere(KEY key, MASK mask);
virtual void setEnabled(BOOL enabled);
virtual LLXMLNodePtr getXML(bool save_children = true) const;
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
void setIndexEnabled(S32 index, BOOL enabled);
// return the index value of the selected item
S32 getSelectedIndex() const { return mSelectedIndex; }
// set the index value programatically
BOOL setSelectedIndex(S32 index, BOOL from_event = FALSE);
@@ -92,14 +79,10 @@ public:
virtual void setValue(const LLSD& value );
virtual LLSD getValue() const;
// Draw the group, but also fix the highlighting based on the control.
void draw();
// You must use this method to add buttons to a radio group.
// Don't use addChild -- it won't set the callback function
// correctly.
LLRadioCtrl* addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font);
LLRadioCtrl* getRadioButton(const S32& index) { return mRadioButtons[index]; }
class LLRadioCtrl* addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font, const std::string& payload = "");
// Update the control as needed. Userdata must be a pointer to the button.
void onClickButton(LLUICtrl* clicked_radio);
@@ -123,14 +106,15 @@ public:
private:
// protected function shared by the two constructors.
void init(BOOL border);
void init(bool border);
S32 mSelectedIndex;
typedef std::vector<LLRadioCtrl*> button_list_t;
typedef std::vector<class LLRadioCtrl*> button_list_t;
button_list_t mRadioButtons;
BOOL mHasBorder;
bool mHasBorder;
bool mAllowDeselect; // user can click on an already selected option to deselect it
};
#endif

View File

@@ -1787,7 +1787,7 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de
child_list_t::const_iterator it, end=childs->end();
for (it=childs->begin(); it!=end; ++it)
{
LLRadioCtrl *ctrl = dynamic_cast<LLRadioCtrl*>(*it);
LLView* ctrl = *it;
if (ctrl && (ctrl->getName() == "texture"))
{
ctrl->setLabelArg("[UPLOADFEE]", fee);

View File

@@ -81,8 +81,6 @@ private:
LLIconCtrl* mIcon;
LLLineEditor* mLineEditor;
LLRadioGroup* mRadioGroup;
LLRadioCtrl* mRadio1;
LLRadioCtrl* mRadio2;
LLScrollContainer* mScroll;
LLScrollListCtrl* mScrollList;
LLTabContainer* mTab;