00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #if !defined(_XRB_RADIOBUTTON_HPP_)
00012 #define _XRB_RADIOBUTTON_HPP_
00013
00014 #include "xrb.hpp"
00015
00016 #include <map>
00017
00018 #include "xrb_button.hpp"
00019 #include "xrb_input_events.hpp"
00020 #include "xrb_key.hpp"
00021
00022 namespace Xrb
00023 {
00024
00025 template <typename T, T sentinel> class RadioButtonGroup;
00026
00027 template <typename T, T sentinel>
00028 class RadioButton : public Button
00029 {
00030 public:
00031
00032 RadioButton (
00033 T id,
00034 RadioButtonGroup<T, sentinel> *group,
00035 ContainerWidget *parent,
00036 std::string const &name = "RadioButton");
00037 RadioButton (
00038 Resource<GLTexture> const &picture,
00039 T id,
00040 RadioButtonGroup<T, sentinel> *group,
00041 ContainerWidget *parent,
00042 std::string const &name = "RadioButton");
00043 virtual ~RadioButton ();
00044
00045 inline bool IsChecked () const { return m_is_checked; }
00046 inline T ID () const { return m_id; }
00047
00049
00050 inline SignalSender1<bool> const *SenderCheckedStateChanged () { return &m_sender_checked_state_changed; }
00051 inline SignalSender0 const *SenderChecked () { return &m_sender_checked; }
00052 inline SignalSender0 const *SenderUnchecked () { return &m_sender_unchecked; }
00053
00055
00057
00058 inline SignalReceiver0 const *ReceiverCheck () { return &m_receiver_check; }
00059
00061
00062 void Check ();
00063
00064 protected:
00065
00066 virtual bool ProcessMouseButtonEvent (EventMouseButton const *e);
00067
00068 virtual void UpdateRenderBackground ();
00069 virtual void UpdateRenderPicture ();
00070
00071
00072 virtual void HandleChangedWidgetSkinWidgetBackground (
00073 WidgetSkin::WidgetBackgroundType widget_background_type);
00074 virtual void HandleChangedWidgetSkinTexture (
00075 WidgetSkin::TextureType texture_type);
00076
00077 private:
00078
00079
00080 void Uncheck ();
00081
00082 void AttachToGroup (RadioButtonGroup<T, sentinel> *group);
00083
00084 void DetachFromGroup (RadioButtonGroup<T, sentinel> *group);
00085
00086 void Initialize (T id, RadioButtonGroup<T, sentinel> *group);
00087
00088
00089 bool m_is_checked;
00090
00091 T m_id;
00092
00093 RadioButtonGroup<T, sentinel> *m_group;
00094
00096
00097 SignalSender1<bool> m_sender_checked_state_changed;
00098 SignalSender0 m_sender_checked;
00099 SignalSender0 m_sender_unchecked;
00100
00102
00104
00105 SignalReceiver0 m_receiver_check;
00106
00108
00109 friend class RadioButtonGroup<T, sentinel>;
00110 };
00111
00112 template <typename T, T sentinel>
00113 class RadioButtonGroup : public SignalHandler
00114 {
00115 public:
00116
00117 RadioButtonGroup ();
00118 ~RadioButtonGroup ();
00119
00120
00121 inline RadioButton<T, sentinel> *CheckedButton () const
00122 {
00123 return m_checked_button;
00124 }
00125
00126 inline T ID () const
00127 {
00128 return m_id;
00129 }
00130
00132
00133 inline SignalSender1<T> const *SenderIDChanged () { return &m_sender_id_changed; }
00134
00136
00138
00139 inline SignalReceiver1<T> const *ReceiverSetID () { return &m_receiver_set_id; }
00140
00142
00143 void SetID (T id);
00144
00145 void AddButton (RadioButton<T, sentinel> *button);
00146 void RemoveButton (RadioButton<T, sentinel> *button);
00147
00148 private:
00149
00150 typedef std::map<T, RadioButton<T, sentinel> *> RadioButtonMap;
00151
00152
00153 RadioButtonMap m_button_map;
00154
00155 RadioButton<T, sentinel> *m_checked_button;
00156
00157
00158
00159 T m_id;
00160
00162
00163 SignalSender1<T> m_sender_id_changed;
00164
00166
00168
00169 SignalReceiver1<T> m_receiver_set_id;
00170
00172 };
00173
00174
00175
00176
00177
00178 template <typename T, T sentinel>
00179 RadioButton<T, sentinel>::RadioButton (
00180 T const id,
00181 RadioButtonGroup<T, sentinel> *const group,
00182 ContainerWidget *const parent,
00183 std::string const &name)
00184 :
00185 Button(Resource<GLTexture>(), parent, name),
00186 m_sender_checked_state_changed(this),
00187 m_sender_checked(this),
00188 m_sender_unchecked(this),
00189 m_receiver_check(&RadioButton<T, sentinel>::Check, this)
00190 {
00191 Initialize(id, group);
00192 }
00193
00194 template <typename T, T sentinel>
00195 RadioButton<T, sentinel>::RadioButton (
00196 Resource<GLTexture> const &picture,
00197 T const id,
00198 RadioButtonGroup<T, sentinel> *const group,
00199 ContainerWidget *const parent,
00200 std::string const &name)
00201 :
00202 Button(picture, parent, name),
00203 m_sender_checked_state_changed(this),
00204 m_sender_checked(this),
00205 m_sender_unchecked(this),
00206 m_receiver_check(&RadioButton<T, sentinel>::Check, this)
00207 {
00208 Initialize(id, group);
00209 }
00210
00211 template <typename T, T sentinel>
00212 RadioButton<T, sentinel>::~RadioButton ()
00213 {
00214 if (m_group != NULL)
00215 {
00216 m_group->RemoveButton(this);
00217 m_group = NULL;
00218 }
00219 }
00220
00221 template <typename T, T sentinel>
00222 void RadioButton<T, sentinel>::Check ()
00223 {
00224 if (!m_is_checked)
00225 {
00226 m_is_checked = true;
00227
00228
00229
00230 if (m_group != NULL)
00231 m_group->SetID(ID());
00232 m_sender_checked_state_changed.Signal(m_is_checked);
00233 m_sender_checked.Signal();
00234 }
00235 UpdateRenderBackground();
00236 UpdateRenderPicture();
00237 }
00238
00239 template <typename T, T sentinel>
00240 bool RadioButton<T, sentinel>::ProcessMouseButtonEvent (
00241 EventMouseButton const *const e)
00242 {
00243
00244 Button::ProcessMouseButtonEvent(e);
00245
00246
00247 if (e->ButtonCode() == Key::LEFTMOUSE && e->IsMouseButtonDownEvent())
00248 Check();
00249
00250 return true;
00251 }
00252
00253 template <typename T, T sentinel>
00254 void RadioButton<T, sentinel>::UpdateRenderBackground ()
00255 {
00256 SetRenderBackground(
00257 WidgetSkinWidgetBackground(WidgetSkin::RADIO_BUTTON_BACKGROUND));
00258 }
00259
00260 template <typename T, T sentinel>
00261 void RadioButton<T, sentinel>::UpdateRenderPicture ()
00262 {
00263 if (IsChecked())
00264 {
00265 if (Picture().IsValid())
00266 SetRenderPicture(Picture());
00267 else
00268 SetRenderPicture(
00269 WidgetSkinTexture(WidgetSkin::RADIO_BUTTON_CHECK_TEXTURE));
00270 }
00271 else
00272 SetRenderPicture(Resource<GLTexture>());
00273 }
00274
00275 template <typename T, T sentinel>
00276 void RadioButton<T, sentinel>::HandleChangedWidgetSkinWidgetBackground (
00277 WidgetSkin::WidgetBackgroundType const widget_background_type)
00278 {
00279 if (widget_background_type == WidgetSkin::RADIO_BUTTON_BACKGROUND)
00280 UpdateRenderBackground();
00281 }
00282
00283 template <typename T, T sentinel>
00284 void RadioButton<T, sentinel>::HandleChangedWidgetSkinTexture (
00285 WidgetSkin::TextureType const texture_type)
00286 {
00287 if (texture_type == WidgetSkin::RADIO_BUTTON_CHECK_TEXTURE)
00288 UpdateRenderPicture();
00289 }
00290
00291 template <typename T, T sentinel>
00292 void RadioButton<T, sentinel>::Uncheck ()
00293 {
00294 if (m_is_checked)
00295 {
00296 m_is_checked = false;
00297
00298 m_sender_checked_state_changed.Signal(m_is_checked);
00299 m_sender_unchecked.Signal();
00300 }
00301 UpdateRenderBackground();
00302 UpdateRenderPicture();
00303 }
00304
00305 template <typename T, T sentinel>
00306 void RadioButton<T, sentinel>::AttachToGroup (
00307 RadioButtonGroup<T, sentinel> *const group)
00308 {
00309 if (m_group != NULL)
00310 m_group->RemoveButton(this);
00311
00312 ASSERT1(group != NULL);
00313 m_group = group;
00314 }
00315
00316 template <typename T, T sentinel>
00317 void RadioButton<T, sentinel>::DetachFromGroup (
00318 RadioButtonGroup<T, sentinel> *const group)
00319 {
00320 ASSERT1(m_group == group);
00321 m_group = NULL;
00322 }
00323
00324 template <typename T, T sentinel>
00325 void RadioButton<T, sentinel>::Initialize (
00326 T id,
00327 RadioButtonGroup<T, sentinel> *const group)
00328 {
00329 ASSERT1(group != NULL);
00330
00331 m_is_checked = false;
00332 RadioButton<T, sentinel>::UpdateRenderBackground();
00333 RadioButton<T, sentinel>::UpdateRenderPicture();
00334
00335 m_id = id;
00336 m_group = group;
00337
00338 m_group->AddButton(this);
00339
00340 FixSize(
00341 ScreenCoordVector2(
00342 WidgetSkinFont(WidgetSkin::DEFAULT_FONT)->PixelHeight(),
00343 WidgetSkinFont(WidgetSkin::DEFAULT_FONT)->PixelHeight()));
00344 }
00345
00346
00347
00348
00349
00350 template <typename T, T sentinel>
00351 RadioButtonGroup<T, sentinel>::RadioButtonGroup ()
00352 :
00353 SignalHandler(),
00354 m_sender_id_changed(this),
00355 m_receiver_set_id(&RadioButtonGroup<T, sentinel>::SetID, this)
00356 {
00357 m_id = sentinel;
00358 m_checked_button = NULL;
00359 }
00360
00361 template <typename T, T sentinel>
00362 RadioButtonGroup<T, sentinel>::~RadioButtonGroup ()
00363 {
00364 m_checked_button = NULL;
00365
00366
00367 for (typename RadioButtonMap::iterator
00368 it = m_button_map.begin(),
00369 it_end = m_button_map.end();
00370 it != it_end;
00371 ++it)
00372 {
00373 RadioButton<T, sentinel> *radio_button = it->second;
00374 ASSERT1(radio_button != NULL);
00375 radio_button->DetachFromGroup(this);
00376 }
00377
00378 m_button_map.clear();
00379 }
00380
00381 template <typename T, T sentinel>
00382 void RadioButtonGroup<T, sentinel>::SetID (T id)
00383 {
00384
00385 if (m_id == id)
00386 return;
00387
00388 RadioButton<T, sentinel> *new_checked_button;
00389
00390
00391 if (id == sentinel)
00392 {
00393 new_checked_button = NULL;
00394 }
00395 else
00396 {
00397
00398 typename RadioButtonMap::iterator it = m_button_map.find(id);
00399 if (it == m_button_map.end())
00400 return;
00401
00402 ASSERT1(it->second != NULL);
00403 new_checked_button = it->second;
00404 }
00405
00406
00407 if (m_checked_button != NULL)
00408 m_checked_button->Uncheck();
00409
00410 m_id = id;
00411 m_checked_button = new_checked_button;
00412
00413
00414 if (m_checked_button != NULL)
00415 m_checked_button->Check();
00416
00417 m_sender_id_changed.Signal(m_id);
00418 }
00419
00420 template <typename T, T sentinel>
00421 void RadioButtonGroup<T, sentinel>::AddButton (
00422 RadioButton<T, sentinel> *const button)
00423 {
00424 ASSERT1(button != NULL);
00425
00426 button->Uncheck();
00427
00428 bool no_buttons_in_group = m_button_map.size() == 0;
00429
00430 typename RadioButtonMap::iterator it = m_button_map.find(button->ID());
00431
00432 ASSERT1(it == m_button_map.end() &&
00433 "You tried to add two RadioButtons with the same ID");
00434 m_button_map[button->ID()] = button;
00435
00436 if (no_buttons_in_group)
00437 SetID(button->ID());
00438 }
00439
00440 template <typename T, T sentinel>
00441 void RadioButtonGroup<T, sentinel>::RemoveButton (
00442 RadioButton<T, sentinel> *const button)
00443 {
00444 ASSERT1(button != NULL);
00445
00446
00447 typename RadioButtonMap::iterator it = m_button_map.find(button->ID());
00448
00449 if (it != m_button_map.end())
00450 {
00451 ASSERT1(it->second != NULL);
00452 it->second->DetachFromGroup(this);
00453 m_button_map.erase(it);
00454 }
00455
00456
00457
00458
00459 SetID(sentinel);
00460 }
00461
00462 }
00463
00464 #endif // !defined(_XRB_RADIOBUTTON_HPP_)
00465