diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llui/lluictrl.cpp | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/linden/indra/llui/lluictrl.cpp b/linden/indra/llui/lluictrl.cpp new file mode 100644 index 0000000..977f523 --- /dev/null +++ b/linden/indra/llui/lluictrl.cpp | |||
@@ -0,0 +1,360 @@ | |||
1 | /** | ||
2 | * @file lluictrl.cpp | ||
3 | * @author James Cook, Richard Nelson, Tom Yedwab | ||
4 | * @brief Abstract base class for UI controls | ||
5 | * | ||
6 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | //#include "llviewerprecompiledheaders.h" | ||
30 | #include "linden_common.h" | ||
31 | |||
32 | #include "lluictrl.h" | ||
33 | |||
34 | #include "llgl.h" | ||
35 | #include "llui.h" | ||
36 | #include "lluiconstants.h" | ||
37 | #include "llfocusmgr.h" | ||
38 | #include "v3color.h" | ||
39 | |||
40 | #include "llstring.h" | ||
41 | #include "llfontgl.h" | ||
42 | #include "llkeyboard.h" | ||
43 | |||
44 | const U32 MAX_STRING_LENGTH = 10; | ||
45 | |||
46 | LLUICtrl::LLUICtrl() : | ||
47 | mCommitCallback(NULL), | ||
48 | mFocusReceivedCallback(NULL), | ||
49 | mFocusChangedCallback(NULL), | ||
50 | mValidateCallback(NULL), | ||
51 | mCallbackUserData(NULL), | ||
52 | mTentative(FALSE), | ||
53 | mTabStop(TRUE), | ||
54 | mIsChrome(FALSE) | ||
55 | { | ||
56 | } | ||
57 | |||
58 | LLUICtrl::LLUICtrl(const LLString& name, const LLRect& rect, BOOL mouse_opaque, | ||
59 | void (*on_commit_callback)(LLUICtrl*, void*), | ||
60 | void* callback_userdata, | ||
61 | U32 reshape) | ||
62 | : // can't make this automatically follow top and left, breaks lots | ||
63 | // of buttons in the UI. JC 7/20/2002 | ||
64 | LLView( name, rect, mouse_opaque, reshape ), | ||
65 | mCommitCallback( on_commit_callback) , | ||
66 | mFocusReceivedCallback( NULL ), | ||
67 | mFocusChangedCallback( NULL ), | ||
68 | mValidateCallback( NULL ), | ||
69 | mCallbackUserData( callback_userdata ), | ||
70 | mTentative( FALSE ), | ||
71 | mTabStop( TRUE ), | ||
72 | mIsChrome(FALSE) | ||
73 | { | ||
74 | } | ||
75 | |||
76 | LLUICtrl::~LLUICtrl() | ||
77 | { | ||
78 | gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() | ||
79 | } | ||
80 | |||
81 | void LLUICtrl::onCommit() | ||
82 | { | ||
83 | if( mCommitCallback ) | ||
84 | { | ||
85 | mCommitCallback( this, mCallbackUserData ); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // virtual | ||
90 | BOOL LLUICtrl::setTextArg( const LLString& key, const LLString& text ) | ||
91 | { | ||
92 | return FALSE; | ||
93 | } | ||
94 | |||
95 | // virtual | ||
96 | BOOL LLUICtrl::setLabelArg( const LLString& key, const LLString& text ) | ||
97 | { | ||
98 | return FALSE; | ||
99 | } | ||
100 | |||
101 | // virtual | ||
102 | LLCtrlSelectionInterface* LLUICtrl::getSelectionInterface() | ||
103 | { | ||
104 | return NULL; | ||
105 | } | ||
106 | |||
107 | // virtual | ||
108 | LLCtrlListInterface* LLUICtrl::getListInterface() | ||
109 | { | ||
110 | return NULL; | ||
111 | } | ||
112 | |||
113 | // virtual | ||
114 | LLCtrlScrollInterface* LLUICtrl::getScrollInterface() | ||
115 | { | ||
116 | return NULL; | ||
117 | } | ||
118 | |||
119 | // virtual | ||
120 | void LLUICtrl::setTabStop( BOOL b ) | ||
121 | { | ||
122 | mTabStop = b; | ||
123 | } | ||
124 | |||
125 | // virtual | ||
126 | BOOL LLUICtrl::hasTabStop() const | ||
127 | { | ||
128 | return mTabStop; | ||
129 | } | ||
130 | |||
131 | // virtual | ||
132 | BOOL LLUICtrl::acceptsTextInput() const | ||
133 | { | ||
134 | return FALSE; | ||
135 | } | ||
136 | |||
137 | // virtual | ||
138 | void LLUICtrl::onTabInto() | ||
139 | { | ||
140 | } | ||
141 | |||
142 | // virtual | ||
143 | void LLUICtrl::clear() | ||
144 | { | ||
145 | } | ||
146 | |||
147 | // virtual | ||
148 | void LLUICtrl::setIsChrome(BOOL is_chrome) | ||
149 | { | ||
150 | mIsChrome = is_chrome; | ||
151 | } | ||
152 | |||
153 | // virtual | ||
154 | BOOL LLUICtrl::getIsChrome() const | ||
155 | { | ||
156 | return mIsChrome; | ||
157 | } | ||
158 | |||
159 | void LLUICtrl::onFocusReceived() | ||
160 | { | ||
161 | if( mFocusReceivedCallback ) | ||
162 | { | ||
163 | mFocusReceivedCallback( this, mCallbackUserData ); | ||
164 | } | ||
165 | if( mFocusChangedCallback ) | ||
166 | { | ||
167 | mFocusChangedCallback( this, mCallbackUserData ); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | void LLUICtrl::onFocusLost() | ||
172 | { | ||
173 | if( mFocusChangedCallback ) | ||
174 | { | ||
175 | mFocusChangedCallback( this, mCallbackUserData ); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | BOOL LLUICtrl::hasFocus() const | ||
180 | { | ||
181 | return (gFocusMgr.childHasKeyboardFocus(this)); | ||
182 | } | ||
183 | |||
184 | void LLUICtrl::setFocus(BOOL b) | ||
185 | { | ||
186 | // focus NEVER goes to ui ctrls that are disabled! | ||
187 | if (!mEnabled) | ||
188 | { | ||
189 | return; | ||
190 | } | ||
191 | if( b ) | ||
192 | { | ||
193 | if (!hasFocus()) | ||
194 | { | ||
195 | gFocusMgr.setKeyboardFocus( this, &LLUICtrl::onFocusLostCallback ); | ||
196 | onFocusReceived(); | ||
197 | } | ||
198 | } | ||
199 | else | ||
200 | { | ||
201 | if( gFocusMgr.childHasKeyboardFocus(this)) | ||
202 | { | ||
203 | gFocusMgr.setKeyboardFocus( NULL, NULL ); | ||
204 | onFocusLost(); | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | // static | ||
210 | void LLUICtrl::onFocusLostCallback( LLUICtrl* old_focus ) | ||
211 | { | ||
212 | old_focus->onFocusLost(); | ||
213 | } | ||
214 | |||
215 | // this comparator uses the crazy disambiguating logic of LLCompareByTabOrder, | ||
216 | // but to switch up the order so that children that have the default tab group come first | ||
217 | // and those that are prior to the default tab group come last | ||
218 | class CompareByDefaultTabGroup: public LLCompareByTabOrder | ||
219 | { | ||
220 | public: | ||
221 | CompareByDefaultTabGroup(LLView::child_tab_order_t order, S32 default_tab_group): | ||
222 | LLCompareByTabOrder(order), | ||
223 | mDefaultTabGroup(default_tab_group) {} | ||
224 | protected: | ||
225 | /*virtual*/ bool compareTabOrders(const LLView::tab_order_t & a, const LLView::tab_order_t & b) const | ||
226 | { | ||
227 | S32 ag = a.first; // tab group for a | ||
228 | S32 bg = b.first; // tab group for b | ||
229 | // these two ifs have the effect of moving elements prior to the default tab group to the end of the list | ||
230 | // (still sorted relative to each other, though) | ||
231 | if(ag < mDefaultTabGroup && bg >= mDefaultTabGroup) return false; | ||
232 | if(bg < mDefaultTabGroup && ag >= mDefaultTabGroup) return true; | ||
233 | return a < b; // sort correctly if they're both on the same side of the default tab group | ||
234 | } | ||
235 | S32 mDefaultTabGroup; | ||
236 | }; | ||
237 | |||
238 | // sorter for plugging into the query | ||
239 | class DefaultTabGroupFirstSorter : public LLQuerySorter, public LLSingleton<DefaultTabGroupFirstSorter> | ||
240 | { | ||
241 | public: | ||
242 | /*virtual*/ void operator() (LLView * parent, viewList_t &children) const | ||
243 | { | ||
244 | children.sort(CompareByDefaultTabGroup(parent->getCtrlOrder(), parent->getDefaultTabGroup())); | ||
245 | } | ||
246 | }; | ||
247 | |||
248 | BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields) | ||
249 | { | ||
250 | // try to select default tab group child | ||
251 | LLCtrlQuery query = LLView::getTabOrderQuery(); | ||
252 | // sort things such that the default tab group is at the front | ||
253 | query.setSorter(DefaultTabGroupFirstSorter::getInstance()); | ||
254 | LLView::child_list_t result = query(this); | ||
255 | if(result.size() > 0) | ||
256 | { | ||
257 | LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front()); | ||
258 | if(!ctrl->hasFocus()) | ||
259 | { | ||
260 | ctrl->setFocus(TRUE); | ||
261 | ctrl->onTabInto(); | ||
262 | gFocusMgr.triggerFocusFlash(); | ||
263 | } | ||
264 | return TRUE; | ||
265 | } | ||
266 | // fall back on default behavior if we didn't find anything | ||
267 | return LLView::focusFirstItem(prefer_text_fields); | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | // Don't let the children handle the tool tip. Handle it here instead. | ||
272 | BOOL LLUICtrl::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen) | ||
273 | { | ||
274 | BOOL handled = FALSE; | ||
275 | if (getVisible() && pointInView( x, y ) ) | ||
276 | { | ||
277 | if( !mToolTipMsg.empty() ) | ||
278 | { | ||
279 | msg = mToolTipMsg; | ||
280 | |||
281 | // Convert rect local to screen coordinates | ||
282 | localPointToScreen( | ||
283 | 0, 0, | ||
284 | &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); | ||
285 | localPointToScreen( | ||
286 | mRect.getWidth(), mRect.getHeight(), | ||
287 | &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) ); | ||
288 | |||
289 | handled = TRUE; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | if (!handled) | ||
294 | { | ||
295 | return LLView::handleToolTip(x, y, msg, sticky_rect_screen); | ||
296 | } | ||
297 | |||
298 | return handled; | ||
299 | }*/ | ||
300 | |||
301 | void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent) | ||
302 | { | ||
303 | BOOL has_tab_stop = hasTabStop(); | ||
304 | node->getAttributeBOOL("tab_stop", has_tab_stop); | ||
305 | |||
306 | setTabStop(has_tab_stop); | ||
307 | |||
308 | LLView::initFromXML(node, parent); | ||
309 | } | ||
310 | |||
311 | LLXMLNodePtr LLUICtrl::getXML(bool save_children) const | ||
312 | { | ||
313 | LLXMLNodePtr node = LLView::getXML(save_children); | ||
314 | node->createChild("tab_stop", TRUE)->setBoolValue(hasTabStop()); | ||
315 | |||
316 | return node; | ||
317 | } | ||
318 | |||
319 | // *NOTE: If other classes derive from LLPanel, they will need to be | ||
320 | // added to this function. | ||
321 | LLPanel* LLUICtrl::getParentPanel() const | ||
322 | { | ||
323 | LLView* parent = getParent(); | ||
324 | while (parent | ||
325 | && parent->getWidgetType() != WIDGET_TYPE_PANEL | ||
326 | && parent->getWidgetType() != WIDGET_TYPE_FLOATER) | ||
327 | { | ||
328 | parent = parent->getParent(); | ||
329 | } | ||
330 | return reinterpret_cast<LLPanel*>(parent); | ||
331 | } | ||
332 | |||
333 | // virtual | ||
334 | void LLUICtrl::setTentative(BOOL b) | ||
335 | { | ||
336 | mTentative = b; | ||
337 | } | ||
338 | |||
339 | // virtual | ||
340 | BOOL LLUICtrl::getTentative() const | ||
341 | { | ||
342 | return mTentative; | ||
343 | } | ||
344 | |||
345 | // virtual | ||
346 | void LLUICtrl::setDoubleClickCallback( void (*cb)(void*) ) | ||
347 | { | ||
348 | } | ||
349 | |||
350 | // virtual | ||
351 | void LLUICtrl::setColor(const LLColor4& color) | ||
352 | { } | ||
353 | |||
354 | // virtual | ||
355 | void LLUICtrl::setMinValue(LLSD min_value) | ||
356 | { } | ||
357 | |||
358 | // virtual | ||
359 | void LLUICtrl::setMaxValue(LLSD max_value) | ||
360 | { } | ||