Panda3D
|
00001 // Filename: pgButton.cxx 00002 // Created by: drose (13Mar02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pgButton.h" 00016 #include "pgMouseWatcherParameter.h" 00017 00018 #include "throw_event.h" 00019 #include "mouseButton.h" 00020 #include "mouseWatcherParameter.h" 00021 #include "colorAttrib.h" 00022 #include "transformState.h" 00023 00024 TypeHandle PGButton::_type_handle; 00025 00026 //////////////////////////////////////////////////////////////////// 00027 // Function: PGButton::Constructor 00028 // Access: Published 00029 // Description: 00030 //////////////////////////////////////////////////////////////////// 00031 PGButton:: 00032 PGButton(const string &name) : PGItem(name) 00033 { 00034 _button_down = false; 00035 _click_buttons.insert(MouseButton::one()); 00036 00037 set_active(true); 00038 } 00039 00040 //////////////////////////////////////////////////////////////////// 00041 // Function: PGButton::Destructor 00042 // Access: Public, Virtual 00043 // Description: 00044 //////////////////////////////////////////////////////////////////// 00045 PGButton:: 00046 ~PGButton() { 00047 } 00048 00049 //////////////////////////////////////////////////////////////////// 00050 // Function: PGButton::Copy Constructor 00051 // Access: Public 00052 // Description: 00053 //////////////////////////////////////////////////////////////////// 00054 PGButton:: 00055 PGButton(const PGButton ©) : 00056 PGItem(copy), 00057 _click_buttons(copy._click_buttons) 00058 { 00059 _button_down = false; 00060 } 00061 00062 //////////////////////////////////////////////////////////////////// 00063 // Function: PGButton::make_copy 00064 // Access: Public, Virtual 00065 // Description: Returns a newly-allocated Node that is a shallow copy 00066 // of this one. It will be a different Node pointer, 00067 // but its internal data may or may not be shared with 00068 // that of the original Node. 00069 //////////////////////////////////////////////////////////////////// 00070 PandaNode *PGButton:: 00071 make_copy() const { 00072 LightReMutexHolder holder(_lock); 00073 return new PGButton(*this); 00074 } 00075 00076 //////////////////////////////////////////////////////////////////// 00077 // Function: PGButton::enter_region 00078 // Access: Public, Virtual 00079 // Description: This is a callback hook function, called whenever the 00080 // mouse enters the region. 00081 //////////////////////////////////////////////////////////////////// 00082 void PGButton:: 00083 enter_region(const MouseWatcherParameter ¶m) { 00084 LightReMutexHolder holder(_lock); 00085 if (get_active()) { 00086 set_state(_button_down ? S_depressed : S_rollover); 00087 } 00088 PGItem::enter_region(param); 00089 } 00090 00091 //////////////////////////////////////////////////////////////////// 00092 // Function: PGButton::exit_region 00093 // Access: Public, Virtual 00094 // Description: This is a callback hook function, called whenever the 00095 // mouse exits the region. 00096 //////////////////////////////////////////////////////////////////// 00097 void PGButton:: 00098 exit_region(const MouseWatcherParameter ¶m) { 00099 LightReMutexHolder holder(_lock); 00100 if (get_active()) { 00101 set_state(S_ready); 00102 } 00103 PGItem::exit_region(param); 00104 } 00105 00106 //////////////////////////////////////////////////////////////////// 00107 // Function: PGButton::press 00108 // Access: Public, Virtual 00109 // Description: This is a callback hook function, called whenever a 00110 // mouse or keyboard button is depressed while the mouse 00111 // is within the region. 00112 //////////////////////////////////////////////////////////////////// 00113 void PGButton:: 00114 press(const MouseWatcherParameter ¶m, bool background) { 00115 LightReMutexHolder holder(_lock); 00116 if (has_click_button(param.get_button())) { 00117 if (get_active()) { 00118 _button_down = true; 00119 set_state(S_depressed); 00120 } 00121 } 00122 PGItem::press(param, background); 00123 } 00124 00125 //////////////////////////////////////////////////////////////////// 00126 // Function: PGButton::release 00127 // Access: Public, Virtual 00128 // Description: This is a callback hook function, called whenever a 00129 // mouse or keyboard button previously depressed with 00130 // press() is released. 00131 //////////////////////////////////////////////////////////////////// 00132 void PGButton:: 00133 release(const MouseWatcherParameter ¶m, bool background) { 00134 LightReMutexHolder holder(_lock); 00135 if (has_click_button(param.get_button())) { 00136 _button_down = false; 00137 if (get_active()) { 00138 if (param.is_outside()) { 00139 set_state(S_ready); 00140 } else { 00141 set_state(S_rollover); 00142 click(param); 00143 } 00144 } 00145 } 00146 PGItem::release(param, background); 00147 } 00148 00149 //////////////////////////////////////////////////////////////////// 00150 // Function: PGButton::click 00151 // Access: Public, Virtual 00152 // Description: This is a callback hook function, called whenever the 00153 // button is clicked down-and-up by the user normally. 00154 //////////////////////////////////////////////////////////////////// 00155 void PGButton:: 00156 click(const MouseWatcherParameter ¶m) { 00157 LightReMutexHolder holder(_lock); 00158 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param); 00159 string event = get_click_event(param.get_button()); 00160 play_sound(event); 00161 throw_event(event, EventParameter(ep)); 00162 00163 if (has_notify()) { 00164 get_notify()->button_click(this, param); 00165 } 00166 } 00167 00168 //////////////////////////////////////////////////////////////////// 00169 // Function: PGButton::setup 00170 // Access: Published 00171 // Description: Sets up the button as a default text button using the 00172 // indicated label string. The TextNode defined by 00173 // PGItem::get_text_node() will be used to create the 00174 // label geometry. This automatically sets up the frame 00175 // according to the size of the text. 00176 //////////////////////////////////////////////////////////////////// 00177 void PGButton:: 00178 setup(const string &label, PN_stdfloat bevel) { 00179 LightReMutexHolder holder(_lock); 00180 clear_state_def(S_ready); 00181 clear_state_def(S_depressed); 00182 clear_state_def(S_rollover); 00183 clear_state_def(S_inactive); 00184 00185 TextNode *text_node = get_text_node(); 00186 text_node->set_text(label); 00187 PT(PandaNode) geom = text_node->generate(); 00188 00189 LVecBase4 frame = text_node->get_card_actual(); 00190 set_frame(frame[0] - 0.4, frame[1] + 0.4, frame[2] - 0.15f, frame[3] + 0.15f); 00191 00192 PT(PandaNode) ready = new PandaNode("ready"); 00193 PT(PandaNode) depressed = new PandaNode("depressed"); 00194 PT(PandaNode) rollover = new PandaNode("rollover"); 00195 PT(PandaNode) inactive = new PandaNode("inactive"); 00196 00197 PGFrameStyle style; 00198 style.set_color(0.8f, 0.8f, 0.8f, 1.0f); 00199 style.set_width(bevel, bevel); 00200 00201 style.set_type(PGFrameStyle::T_bevel_out); 00202 set_frame_style(S_ready, style); 00203 00204 style.set_color(0.9f, 0.9f, 0.9f, 1.0f); 00205 set_frame_style(S_rollover, style); 00206 00207 inactive->set_attrib(ColorAttrib::make_flat(LColor(0.8f, 0.8f, 0.8f, 1.0f))); 00208 style.set_color(0.6f, 0.6f, 0.6f, 1.0f); 00209 set_frame_style(S_inactive, style); 00210 00211 style.set_type(PGFrameStyle::T_bevel_in); 00212 style.set_color(0.8f, 0.8f, 0.8f, 1.0f); 00213 set_frame_style(S_depressed, style); 00214 depressed->set_transform(TransformState::make_pos(LVector3(0.05f, 0.0f, -0.05f))); 00215 00216 get_state_def(S_ready).attach_new_node(ready, 1); 00217 get_state_def(S_depressed).attach_new_node(depressed, 1); 00218 get_state_def(S_rollover).attach_new_node(rollover, 1); 00219 get_state_def(S_inactive).attach_new_node(inactive, 1); 00220 00221 ready->add_child(geom); 00222 depressed->add_child(geom); 00223 rollover->add_child(geom); 00224 inactive->add_child(geom); 00225 } 00226 00227 //////////////////////////////////////////////////////////////////// 00228 // Function: PGButton::setup 00229 // Access: Published 00230 // Description: Sets up the button using the indicated NodePath as 00231 // arbitrary geometry. 00232 //////////////////////////////////////////////////////////////////// 00233 void PGButton:: 00234 setup(const NodePath &ready, const NodePath &depressed, 00235 const NodePath &rollover, const NodePath &inactive) { 00236 LightReMutexHolder holder(_lock); 00237 clear_state_def(S_ready); 00238 clear_state_def(S_depressed); 00239 clear_state_def(S_rollover); 00240 clear_state_def(S_inactive); 00241 00242 instance_to_state_def(S_ready, ready); 00243 instance_to_state_def(S_depressed, depressed); 00244 instance_to_state_def(S_rollover, rollover); 00245 instance_to_state_def(S_inactive, inactive); 00246 00247 // Set the button frame size. 00248 LPoint3 min_point, max_point; 00249 ready.calc_tight_bounds(min_point, max_point); 00250 set_frame(min_point[0], max_point[0], 00251 min_point[2], max_point[2]); 00252 } 00253 00254 //////////////////////////////////////////////////////////////////// 00255 // Function: PGButton::set_active 00256 // Access: Published, Virtual 00257 // Description: Toggles the active/inactive state of the button. In 00258 // the case of a PGButton, this also changes its visual 00259 // appearance. 00260 //////////////////////////////////////////////////////////////////// 00261 void PGButton:: 00262 set_active(bool active) { 00263 LightReMutexHolder holder(_lock); 00264 if (active != get_active()) { 00265 PGItem::set_active(active); 00266 set_state(active ? S_ready : S_inactive); 00267 } 00268 } 00269 00270 //////////////////////////////////////////////////////////////////// 00271 // Function: PGButton::add_click_button 00272 // Access: Published 00273 // Description: Adds the indicated button to the set of buttons that 00274 // can effectively "click" the PGButton. Normally, this 00275 // is just MouseButton::one(). Returns true if the 00276 // button was added, or false if it was already there. 00277 //////////////////////////////////////////////////////////////////// 00278 bool PGButton:: 00279 add_click_button(const ButtonHandle &button) { 00280 LightReMutexHolder holder(_lock); 00281 return _click_buttons.insert(button).second; 00282 } 00283 00284 //////////////////////////////////////////////////////////////////// 00285 // Function: PGButton::remove_click_button 00286 // Access: Published 00287 // Description: Removes the indicated button from the set of buttons 00288 // that can effectively "click" the PGButton. Normally, 00289 // this is just MouseButton::one(). Returns true if the 00290 // button was removed, or false if it was not in the 00291 // set. 00292 //////////////////////////////////////////////////////////////////// 00293 bool PGButton:: 00294 remove_click_button(const ButtonHandle &button) { 00295 LightReMutexHolder holder(_lock); 00296 return (_click_buttons.erase(button) != 0); 00297 } 00298 00299 //////////////////////////////////////////////////////////////////// 00300 // Function: PGButton::has_click_button 00301 // Access: Published 00302 // Description: Returns true if the indicated button is on the set of 00303 // buttons that can effectively "click" the PGButton. 00304 // Normally, this is just MouseButton::one(). 00305 //////////////////////////////////////////////////////////////////// 00306 bool PGButton:: 00307 has_click_button(const ButtonHandle &button) { 00308 LightReMutexHolder holder(_lock); 00309 return (_click_buttons.count(button) != 0); 00310 } 00311