llradiogroup.cpp

Go to the documentation of this file.
00001 
00033 #include "linden_common.h"
00034 
00035 #include "llboost.h"
00036 
00037 #include "llradiogroup.h"
00038 #include "indra_constants.h"
00039 
00040 #include "llviewborder.h"
00041 #include "llcontrol.h"
00042 #include "llui.h"
00043 #include "llfocusmgr.h"
00044 
00045 static LLRegisterWidget<LLRadioGroup> r("radio_group");
00046 
00047 LLRadioGroup::LLRadioGroup(const LLString& name, const LLRect& rect,
00048                                                    const LLString& control_name,
00049                                                    LLUICtrlCallback callback,
00050                                                    void* userdata,
00051                                                    BOOL border)
00052 :       LLUICtrl(name, rect, TRUE, callback, userdata, FOLLOWS_LEFT | FOLLOWS_TOP),
00053         mSelectedIndex(0)
00054 {
00055         setControlName(control_name, NULL);
00056         init(border);
00057 }
00058 
00059 LLRadioGroup::LLRadioGroup(const LLString& name, const LLRect& rect,
00060                                                    S32 initial_index,
00061                                                    LLUICtrlCallback callback,
00062                                                    void* userdata,
00063                                                    BOOL border) :
00064         LLUICtrl(name, rect, TRUE, callback, userdata, FOLLOWS_LEFT | FOLLOWS_TOP),
00065         mSelectedIndex(initial_index)
00066 {
00067         init(border);
00068 }
00069 
00070 void LLRadioGroup::init(BOOL border)
00071 {
00072         if (border)
00073         {
00074                 addChild( new LLViewBorder( "radio group border", 
00075                                                                         LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), 
00076                                                                         LLViewBorder::BEVEL_NONE, 
00077                                                                         LLViewBorder::STYLE_LINE, 
00078                                                                         1 ) );
00079         }
00080         mHasBorder = border;
00081 }
00082 
00083 
00084 
00085 
00086 LLRadioGroup::~LLRadioGroup()
00087 {
00088 }
00089 
00090 
00091 // virtual
00092 void LLRadioGroup::setEnabled(BOOL enabled)
00093 {
00094         for (child_list_const_iter_t child_iter = getChildList()->begin();
00095                  child_iter != getChildList()->end(); ++child_iter)
00096         {
00097                 LLView *child = *child_iter;
00098                 child->setEnabled(enabled);
00099         }
00100         LLView::setEnabled(enabled);
00101 }
00102 
00103 void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled)
00104 {
00105         S32 count = 0;
00106         for (button_list_t::iterator iter = mRadioButtons.begin();
00107                  iter != mRadioButtons.end(); ++iter)
00108         {
00109                 LLRadioCtrl* child = *iter;
00110                 if (count == index)
00111                 {
00112                         child->setEnabled(enabled);
00113                         if (index == mSelectedIndex && enabled == FALSE)
00114                         {
00115                                 setSelectedIndex(-1);
00116                         }
00117                         break;
00118                 }
00119                 count++;
00120         }
00121         count = 0;
00122         if (mSelectedIndex < 0)
00123         {
00124                 // Set to highest enabled value < index,
00125                 // or lowest value above index if none lower are enabled
00126                 // or 0 if none are enabled
00127                 for (button_list_t::iterator iter = mRadioButtons.begin();
00128                          iter != mRadioButtons.end(); ++iter)
00129                 {
00130                         LLRadioCtrl* child = *iter;
00131                         if (count >= index && mSelectedIndex >= 0)
00132                         {
00133                                 break;
00134                         }
00135                         if (child->getEnabled())
00136                         {
00137                                 setSelectedIndex(count);
00138                         }
00139                         count++;
00140                 }
00141                 if (mSelectedIndex < 0)
00142                 {
00143                         setSelectedIndex(0);
00144                 }
00145         }
00146 }
00147 
00148 BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event)
00149 {
00150         if (index < 0 || index >= (S32)mRadioButtons.size())
00151         {
00152                 return FALSE;
00153         }
00154 
00155         mSelectedIndex = index;
00156 
00157         if (!from_event)
00158         {
00159                 setControlValue(getSelectedIndex());
00160         }
00161 
00162         return TRUE;
00163 }
00164 
00165 BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask)
00166 {
00167         BOOL handled = FALSE;
00168         // do any of the tab buttons have keyboard focus?
00169         if (mask == MASK_NONE)
00170         {
00171                 switch(key)
00172                 {
00173                 case KEY_DOWN:
00174                         if (!setSelectedIndex((getSelectedIndex() + 1)))
00175                         {
00176                                 make_ui_sound("UISndInvalidOp");
00177                         }
00178                         else
00179                         {
00180                                 onCommit();
00181                         }
00182                         handled = TRUE;
00183                         break;
00184                 case KEY_UP:
00185                         if (!setSelectedIndex((getSelectedIndex() - 1)))
00186                         {
00187                                 make_ui_sound("UISndInvalidOp");
00188                         }
00189                         else
00190                         {
00191                                 onCommit();
00192                         }
00193                         handled = TRUE;
00194                         break;
00195                 case KEY_LEFT:
00196                         if (!setSelectedIndex((getSelectedIndex() - 1)))
00197                         {
00198                                 make_ui_sound("UISndInvalidOp");
00199                         }
00200                         else
00201                         {
00202                                 onCommit();
00203                         }
00204                         handled = TRUE;
00205                         break;
00206                 case KEY_RIGHT:
00207                         if (!setSelectedIndex((getSelectedIndex() + 1)))
00208                         {
00209                                 make_ui_sound("UISndInvalidOp");
00210                         }
00211                         else
00212                         {
00213                                 onCommit();
00214                         }
00215                         handled = TRUE;
00216                         break;
00217                 default:
00218                         break;
00219                 }
00220         }
00221         return handled;
00222 }
00223 
00224 void LLRadioGroup::draw()
00225 {
00226         S32 current_button = 0;
00227 
00228         BOOL take_focus = FALSE;
00229         if (gFocusMgr.childHasKeyboardFocus(this))
00230         {
00231                 take_focus = TRUE;
00232         }
00233 
00234         for (button_list_t::iterator iter = mRadioButtons.begin();
00235                  iter != mRadioButtons.end(); ++iter)
00236         {
00237                 LLRadioCtrl* radio = *iter;
00238                 BOOL selected = (current_button == mSelectedIndex);
00239                 radio->setValue( selected );
00240                 if (take_focus && selected && !gFocusMgr.childHasKeyboardFocus(radio))
00241                 {
00242                         // don't flash keyboard focus when navigating via keyboard
00243                         BOOL DONT_FLASH = FALSE;
00244                         radio->focusFirstItem(FALSE, DONT_FLASH);
00245                 }
00246                 current_button++;
00247         }
00248 
00249         LLView::draw();
00250 }
00251 
00252 
00253 // When adding a button, we need to ensure that the radio
00254 // group gets a message when the button is clicked.
00255 LLRadioCtrl* LLRadioGroup::addRadioButton(const LLString& name, const LLString& label, const LLRect& rect, const LLFontGL* font )
00256 {
00257         // Highlight will get fixed in draw method above
00258         LLRadioCtrl* radio = new LLRadioCtrl(name, rect, label, font,
00259                 onClickButton, this);
00260         addChild(radio);
00261         mRadioButtons.push_back(radio);
00262         return radio;
00263 }
00264 
00265 // Handle one button being clicked.  All child buttons must have this
00266 // function as their callback function.
00267 
00268 // static
00269 void LLRadioGroup::onClickButton(LLUICtrl* ui_ctrl, void* userdata)
00270 {
00271         // llinfos << "LLRadioGroup::onClickButton" << llendl;
00272 
00273         LLRadioCtrl* clickedRadio = (LLRadioCtrl*) ui_ctrl;
00274         LLRadioGroup* self = (LLRadioGroup*) userdata;
00275 
00276         S32 counter = 0;
00277         for (button_list_t::iterator iter = self->mRadioButtons.begin();
00278                  iter != self->mRadioButtons.end(); ++iter)
00279         {
00280                 LLRadioCtrl* radio = *iter;
00281                 if (radio == clickedRadio)
00282                 {
00283                         // llinfos << "clicked button " << counter << llendl;
00284                         self->setSelectedIndex(counter);
00285                         self->setControlValue(counter);
00286                         
00287                         // BUG: Calls click callback even if button didn't actually change
00288                         self->onCommit();
00289 
00290                         return;
00291                 }
00292 
00293                 counter++;
00294         }
00295 
00296         llwarns << "LLRadioGroup::onClickButton - clicked button that isn't a child" << llendl;
00297 }
00298 
00299 void LLRadioGroup::setValue( const LLSD& value )
00300 {
00301         LLString value_name = value.asString();
00302         int idx = 0;
00303         for (button_list_t::const_iterator iter = mRadioButtons.begin();
00304                  iter != mRadioButtons.end(); ++iter)
00305         {
00306                 LLRadioCtrl* radio = *iter;
00307                 if (radio->getName() == value_name)
00308                 {
00309                         setSelectedIndex(idx);
00310                         idx = -1;
00311                         break;
00312                 }
00313                 ++idx;
00314         }
00315         if (idx != -1)
00316         {
00317                 // string not found, try integer
00318                 if (value.isInteger())
00319                 {
00320                         setSelectedIndex((S32) value.asInteger(), TRUE);
00321                 }
00322                 else
00323                 {
00324                         llwarns << "LLRadioGroup::setValue: value not found: " << value_name << llendl;
00325                 }
00326         }
00327 }
00328 
00329 LLSD LLRadioGroup::getValue() const
00330 {
00331         int index = getSelectedIndex();
00332         int idx = 0;
00333         for (button_list_t::const_iterator iter = mRadioButtons.begin();
00334                  iter != mRadioButtons.end(); ++iter)
00335         {
00336                 if (idx == index) return LLSD((*iter)->getName());
00337                 ++idx;
00338         }
00339         return LLSD();
00340 }
00341 
00342 // virtual
00343 LLXMLNodePtr LLRadioGroup::getXML(bool save_children) const
00344 {
00345         LLXMLNodePtr node = LLUICtrl::getXML();
00346 
00347         // Attributes
00348 
00349         node->createChild("draw_border", TRUE)->setBoolValue(mHasBorder);
00350 
00351         // Contents
00352 
00353         for (button_list_t::const_iterator iter = mRadioButtons.begin();
00354                  iter != mRadioButtons.end(); ++iter)
00355         {
00356                 LLRadioCtrl* radio = *iter;
00357 
00358                 LLXMLNodePtr child_node = radio->LLView::getXML();
00359                 child_node->setStringValue(radio->getLabel());
00360                 child_node->setName("radio_item");
00361 
00362                 node->addChild(child_node);
00363         }
00364 
00365         return node;
00366 }
00367 
00368 // static
00369 LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
00370 {
00371         LLString name("radio_group");
00372         node->getAttributeString("name", name);
00373 
00374         U32 initial_value = 0;
00375         node->getAttributeU32("initial_value", initial_value);
00376 
00377         BOOL draw_border = TRUE;
00378         node->getAttributeBOOL("draw_border", draw_border);
00379 
00380         LLRect rect;
00381         createRect(node, rect, parent, LLRect());
00382 
00383         LLRadioGroup* radio_group = new LLRadioGroup(name, 
00384                 rect,
00385                 initial_value,
00386                 NULL,
00387                 NULL,
00388                 draw_border);
00389 
00390         const LLString& contents = node->getValue();
00391 
00392         LLRect group_rect = radio_group->getRect();
00393 
00394         LLFontGL *font = LLView::selectFont(node);
00395 
00396         if (contents.find_first_not_of(" \n\t") != contents.npos)
00397         {
00398                 // ...old school default vertical layout
00399                 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00400                 boost::char_separator<char> sep("\t\n");
00401                 tokenizer tokens(contents, sep);
00402                 tokenizer::iterator token_iter = tokens.begin();
00403         
00404                 const S32 HPAD = 4, VPAD = 4;
00405                 S32 cur_y = group_rect.getHeight() - VPAD;
00406         
00407                 while(token_iter != tokens.end())
00408                 {
00409                         const char* line = token_iter->c_str();
00410                         LLRect rect(HPAD, cur_y, group_rect.getWidth() - (2 * HPAD), cur_y - 15);
00411                         cur_y -= VPAD + 15;
00412                         radio_group->addRadioButton("radio", line, rect, font);
00413                         ++token_iter;
00414                 }
00415                 llwarns << "Legacy radio group format used! Please convert to use <radio_item> tags!" << llendl;
00416         }
00417         else
00418         {
00419                 // ...per pixel layout
00420                 LLXMLNodePtr child;
00421                 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
00422                 {
00423                         if (child->hasName("radio_item"))
00424                         {
00425                                 LLRect item_rect;
00426                                 createRect(child, item_rect, radio_group, rect);
00427 
00428                                 LLString radioname("radio");
00429                                 child->getAttributeString("name", radioname);
00430                                 LLString item_label = child->getTextContents();
00431                                 LLRadioCtrl* radio = radio_group->addRadioButton(radioname, item_label.c_str(), item_rect, font);
00432 
00433                                 radio->initFromXML(child, radio_group);
00434                         }
00435                 }
00436         }
00437 
00438         radio_group->initFromXML(node, parent);
00439 
00440         return radio_group;
00441 }
00442 
00443 // LLCtrlSelectionInterface functions
00444 BOOL    LLRadioGroup::setCurrentByID( const LLUUID& id )
00445 {
00446         return FALSE;
00447 }
00448 
00449 LLUUID  LLRadioGroup::getCurrentID() const
00450 {
00451         return LLUUID::null;
00452 }
00453 
00454 BOOL    LLRadioGroup::setSelectedByValue(const LLSD& value, BOOL selected)
00455 {
00456         S32 idx = 0;
00457         std::string value_string = value.asString();
00458         for (button_list_t::const_iterator iter = mRadioButtons.begin();
00459                  iter != mRadioButtons.end(); ++iter)
00460         {
00461                 if((*iter)->getName() == value_string)
00462                 {
00463                         setSelectedIndex(idx);
00464                         return TRUE;
00465                 }
00466                 idx++;
00467         }
00468 
00469         return FALSE;
00470 }
00471 
00472 LLSD    LLRadioGroup::getSelectedValue()
00473 {
00474         return getValue();      
00475 }
00476 
00477 BOOL    LLRadioGroup::isSelected(const LLSD& value) const
00478 {
00479         S32 idx = 0;
00480         std::string value_string = value.asString();
00481         for (button_list_t::const_iterator iter = mRadioButtons.begin();
00482                  iter != mRadioButtons.end(); ++iter)
00483         {
00484                 if((*iter)->getName() == value_string)
00485                 {
00486                         if (idx == mSelectedIndex) 
00487                         {
00488                                 return TRUE;
00489                         }
00490                 }
00491                 idx++;
00492         }
00493         return FALSE;
00494 }
00495 
00496 BOOL    LLRadioGroup::operateOnSelection(EOperation op)
00497 {
00498         return FALSE;
00499 }
00500 
00501 BOOL    LLRadioGroup::operateOnAll(EOperation op)
00502 {
00503         return FALSE;
00504 }
00505 
00506 
00507 LLRadioCtrl::~LLRadioCtrl()
00508 {
00509 }
00510 
00511 void LLRadioCtrl::setValue(const LLSD& value)
00512 {
00513         LLCheckBoxCtrl::setValue(value);
00514         mButton->setTabStop(value.asBoolean());
00515 }
00516 

Generated on Fri May 16 08:32:55 2008 for SecondLife by  doxygen 1.5.5