summaryrefslogtreecommitdiff
path: root/indra/newview/llbottomtray.h
blob: 83a33845bf0f458d0394194652f9237784192b23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
/** 
* @file llbottomtray.h
* @brief LLBottomTray class header file
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
* 
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
* 
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
* 
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
* 
* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
* $/LicenseInfo$
*/

#ifndef LL_LLBOTTOMPANEL_H
#define LL_LLBOTTOMPANEL_H

#include "llpanel.h"
#include "llimview.h"
#include "llbutton.h"

class LLChicletPanel;
class LLLayoutStack;
class LLSpeakButton;
class LLNearbyChatBar;
class LLIMChiclet;
class LLBottomTrayLite;
class LLLayoutPanel;
class LLMenuGL;
class LLNearbyChatBarListener;

// Build time optimization, generate once in .cpp file
#ifndef LLBOTTOMTRAY_CPP
extern template class LLBottomTray* LLSingleton<class LLBottomTray>::getInstance();
#endif

/**
 * Class for buttons that should have drag'n'drop ability in bottomtray.
 * These buttons pass mouse events handling to bottomtray.
 */
class LLBottomtrayButton : public LLButton
{
public:
	struct Params : public LLInitParam::Block<Params, LLButton::Params>
	{
		Optional<bool> can_drag;
		Params()
		: can_drag("can_drag", true){}
	};
	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
	/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
	/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);

protected:
	LLBottomtrayButton(const Params& p)
	:	LLButton(p),
		mCanDrag(p.can_drag)
	{

	}
	friend class LLUICtrlFactory;

	bool mCanDrag;
};

class LLBottomTray 
	: public LLSingleton<LLBottomTray>
	, public LLPanel
	, public LLIMSessionObserver
	, public LLVoiceClientStatusObserver
{
	LOG_CLASS(LLBottomTray);
	friend class LLSingleton<LLBottomTray>;
	friend class LLBottomTrayLite;
public:
	~LLBottomTray();

	BOOL postBuild();

	LLChicletPanel*		getChicletPanel()	{return mChicletPanel;}
	LLNearbyChatBar*		getNearbyChatBar();

	void onCommitGesture(LLUICtrl* ctrl);

	// LLIMSessionObserver observe triggers
	virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
	virtual void sessionRemoved(const LLUUID& session_id);
	void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);

	S32 getTotalUnreadIMCount();

	virtual void reshape(S32 width, S32 height, BOOL called_from_parent);

	virtual void setVisible(BOOL visible);

	/*virtual*/ S32 notifyParent(const LLSD& info);

	// Implements LLVoiceClientStatusObserver::onChange() to enable the speak
	// button when voice is available
	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);

	void showBottomTrayContextMenu(S32 x, S32 y, MASK mask);

	void showGestureButton(BOOL visible);
	void showMoveButton(BOOL visible);
	void showCameraButton(BOOL visible);
	void showSnapshotButton(BOOL visible);
	void showSpeakButton(bool visible);

	void toggleMovementControls();
	void toggleCameraControls();

	void onMouselookModeIn();
	void onMouselookModeOut();

	/**
	 * Creates IM Chiclet based on session type (IM chat or Group chat)
	 */
	LLIMChiclet* createIMChiclet(const LLUUID& session_id);

	// Below are methods that were introduced or overriden in bottomtray to handle drag'n'drop

	virtual void draw();

	/**
	 * These three methods handle drag'n'drop, they may be called directly from child buttons.
	 * handleHover and other virtual handle* couldn't be used here, because we should call LLPanel::handle*,
	 * but x and y here are often outside of bottomtray.
	 */
	void onDraggableButtonHover(S32 x, S32 y);
	void onDraggableButtonMouseDown(LLUICtrl* button, S32 x, S32 y);
	void onDraggableButtonMouseUp(LLUICtrl* button, S32 x, S32 y);


private:
	typedef enum e_resize_status_type
	{
		  RS_NORESIZE			= 0x0000
		, RS_CHICLET_PANEL		= 0x0001
		, RS_CHATBAR_INPUT		= 0x0002
		, RS_BUTTON_SNAPSHOT	= 0x0004
		, RS_BUTTON_CAMERA		= 0x0008
		, RS_BUTTON_MOVEMENT	= 0x0010
		, RS_BUTTON_GESTURES	= 0x0020
		, RS_BUTTON_SPEAK		= 0x0040
		, RS_IM_WELL			= 0x0080
		, RS_NOTIFICATION_WELL	= 0x0100
		, RS_BUTTON_BUILD		= 0x0200
		, RS_BUTTON_SEARCH		= 0x0400
		, RS_BUTTON_WORLD_MAP	= 0x0800
		, RS_BUTTON_MINI_MAP	= 0x1000

		/*
		Once new button that can be hidden on resize is added don't forget to update related places:
			- RS_BUTTONS_CAN_BE_HIDDEN enum value below.
			- initResizeStateContainers(): mStateProcessedObjectMap and mButtonsProcessOrder
		*/

		/**
		 * Specifies buttons which can be hidden when bottom tray is shrunk.
		 * They are: Gestures, Movement (Move), Camera (View), Snapshot
		 *		new: Build, Search, Map, World Map, Mini-Map.
		 */
		, RS_BUTTONS_CAN_BE_HIDDEN = RS_BUTTON_SNAPSHOT | RS_BUTTON_CAMERA | RS_BUTTON_MOVEMENT | RS_BUTTON_GESTURES
									| RS_BUTTON_BUILD | RS_BUTTON_SEARCH | RS_BUTTON_WORLD_MAP | RS_BUTTON_MINI_MAP
	}EResizeState;

	// Below are three methods that were introduced to handle drag'n'drop

	/**
	 * finds a panel under the specified LOCAL point
	 */
	LLPanel* findChildPanelByLocalCoords(S32 x, S32 y);

	/**
	 * checks whether the cursor is over an area where the dragged button may be dropped
	 */
	bool isCursorOverDraggableArea(S32 x, S32 y);

	/**
	 * Updates process(shrink/show/hide) order of buttons and order in which they'll be stored for further save/load.
	 * It is called when dragged button is dropped
	 */
	void updateButtonsOrdersAfterDnD();

	// saves order of buttons to file on disk
	void saveButtonsOrder();
	// reads order of buttons from file on disk
	void loadButtonsOrder();

	/**
	 * Updates child controls size and visibility when it is necessary to reduce total width.
	 *
	 * Process order:
	 *	- reduce chiclet panel to its minimal width;
	 *  - reduce chatbar to its minimal width;
	 *  - reduce visible buttons from right to left to their minimal width;
	 *  - hide visible buttons from right to left;
	 * When button is hidden chatbar extended to fill released space if it is necessary.
	 *
	 * @param[in] delta_width - value by which bottom tray should be shrunk. It is a negative value.
	 * @return positive value which bottom tray can not process when it reaches its minimal width.
	 *		Zero if there was enough space to process delta_width.
	 */
	S32 processWidthDecreased(S32 delta_width);

	/**
	 * Updates child controls size and visibility when it is necessary to extend total width.
	 *
	 * Process order:
	 *  - show invisible buttons should be shown from left to right if possible;
	 *  - extend visible buttons from left to right to their default width;
	 *  - extend chatbar to its maximal width;
	 *	- extend chiclet panel to all available space;
	 * When chatbar & chiclet panels are wider then their minimal width they can be reduced to allow
	 * a button gets visible in case if passed delta_width is not enough (chatbar first).
	 *
	 * @param[in] delta_width - value by which bottom tray should be extended. It is a positive value.
	 */
	void processWidthIncreased(S32 delta_width);

	/** helper function to log debug messages */
	void log(LLView* panel, const std::string& descr);

	/**
	 * Tries to show hidden by resize buttons using available width.
	 *
	 * Gets buttons visible if there is enough space. Reduces available_width in this case.
	 *
	 * @params[in, out] available_width - reference to available width to be used to show buttons.
	 * @see processShowButton()
	 */
	void processShowButtons(S32& available_width);

	/**
	 * Tries to show panel with specified button using available width.
	 *
	 * Shows button specified by type if there is enough space. Reduces available_width in this case.
	 *
	 * @params[in] shown_object_type - type of button to be shown.
	 * @params[in, out] available_width - reference to available width to be used to show button.
	 *
	 * @return true if button can be shown, false otherwise
	 */
	bool processShowButton(EResizeState shown_object_type, S32& available_width);

	/**
	 * Hides visible panels with all buttons that may be hidden by resize if it is necessary.
	 *
	 * When button gets hidden some space is released in bottom tray.
	 * This space is taken into account for several consecutive calls for several buttons.
	 *
	 * @params[in, out] required_width - reference to required width to be released. This is a negative value.
	 *			Its absolute value is decreased by shown panel width.
	 * @params[in, out] buttons_freed_width - reference to value released over required one.
	 *			If panel's width is more than required difference is added to buttons_freed_width.
	 * @see processHideButton()
	 */
	void processHideButtons(S32& required_width, S32& buttons_freed_width);

	/**
	 * Hides panel with specified button if it is visible.
	 *
	 * When button gets hidden some space is released in bottom tray.
	 * This space is taken into account for several consecutive calls for several buttons.
	 *
	 * @params[in] processed_object_type - type of button to be hide.
	 * @params[in, out] required_width - reference to required width to be released. This is a negative value.
	 *			Its absolute value is decreased by panel width.
	 * @params[in, out] buttons_freed_width - reference to value released over required one.
	 *			If panel's width is more than required difference is added to buttons_freed_width.
	 */
	void processHideButton(EResizeState processed_object_type, S32& required_width, S32& buttons_freed_width);

	/**
	 * Shrinks shown buttons to reduce total taken space.
	 *
	 * Shrinks buttons that may be shrunk smoothly first. Then shrinks Speak button.
	 *
	 * @param[in, out] required_width - reference to width value which should be released when buttons are shrunk. It is a negative value.
	 * It is increased on the value processed by buttons.
	 * @params[in, out] buttons_freed_width - reference to value released over required one.
	 *			If width of panel with Speak button is more than required that difference is added
	 *				to buttons_freed_width.
	 *			This is because Speak button shrinks discretely unlike other buttons which are changed smoothly.
	 */
	void processShrinkButtons(S32& required_width, S32& buttons_freed_width);

	/**
	 * Shrinks panel with specified button if it is visible.
	 *
	 * @params[in] processed_object_type - type of button to be shrunk.
	 * @param[in, out] required_width - reference to width value which should be released when button is shrunk. It is a negative value.
	 * It is increased on the value released by the button.
	 */
	void processShrinkButton(EResizeState processed_object_type, S32& required_width);

	/**
	 * Extends shown buttons to increase total taken space.
	 *
	 * Extends buttons that may be extended smoothly first. Then extends Speak button.
	 *
	 * @param[in, out] available_width - reference to width value which buttons can use to be extended.
	 *		It is a positive value. It is decreased on the value processed by buttons.
	 */
	void processExtendButtons(S32& available_width);

	/**
	 * Extends shown button to increase total taken space.
	 *
	 * @params[in] processed_object_type - type of button to be extended.
	 * @param[in, out] available_width - reference to width value which button can use to be extended.
	 *		It is a positive value. It is decreased on the value processed by buttons.
	 */
	void processExtendButton(EResizeState processed_object_type, S32& available_width);

	/**
	 * Determines if specified by type object can be shown. It should be hidden by shrink before.
	 *
	 * Processes buttons a such way to show buttons in constant order:
	 *   - Gestures, Move, View, Snapshot
	 */
	bool canButtonBeShown(EResizeState processed_object_type) const;

	/**
	 * Initializes all containers stored data related to children resize state.
	 *
	 * @see mStateProcessedObjectMap
	 * @see mObjectDefaultWidthMap
	 * @see mButtonsProcessOrder
	 */
	void initResizeStateContainers();

	/**
	 * Initializes buttons' visibility depend on stored Control Settings.
	 */
	void initButtonsVisibility();

	/**
	 * Initializes listeners of Control Settings to toggle appropriate buttons' visibility.
	 *
	 * @see toggleShowButton()
	 */
	void setButtonsControlsAndListeners();

	/**
	 * Toggles visibility of specified button depend on passed value.
	 *
	 * @param button_type - type of button to be toggled
	 * @param new_visibility - new visibility of the button
	 *
	 * @see setButtonsControlsAndListeners()
	 */
	static bool toggleShowButton(EResizeState button_type, const LLSD& new_visibility);

	/**
	 * Sets passed visibility to object specified by resize type.
	 */
	void setTrayButtonVisible(EResizeState shown_object_type, bool visible);

	/**
	 * Sets passed visibility to object specified by resize type if it is possible.
	 *
	 * If it is impossible to show required button due to there is no enough room in bottom tray
	 * it will no be shown. Is called via context menu commands.
	 * In this case Alert Dialog will be shown to notify user about that.
	 *
	 * Method also stores resize state to be processed while future bottom tray extending:
	 *  - if hidden while resizing button should be hidden it will not be shown while extending;
	 *  - if hidden via context menu button should be shown but there is no enough room for now
	 *    it will be shown while extending.
	 */
	void setTrayButtonVisibleIfPossible(EResizeState shown_object_type, bool visible, bool raise_notification = true);

	/**
	 * Sets passed visibility to required button and fit widths of shown
	 * buttons(notice that method can shrink widths to
	 * allocate needed room in bottom tray).
	 * Returns true if visibility of required button was set.
	 */
	bool setVisibleAndFitWidths(EResizeState object_type, bool visible);

	/**
	 * Get panel containing the given button.
	 *
	 * @see mStateProcessedObjectMap
	 */
	LLPanel* getButtonPanel(EResizeState button_type);

	/**
	 * Shows/hides panel with specified well button (IM or Notification)
	 *
	 * @param[in] object_type - type of well button to be processed.
	 *		Must be one of RS_IM_WELL or RS_NOTIFICATION_WELL.
	 * @param[in] visible - flag specified whether button should be shown or hidden.
	 */
	void showWellButton(EResizeState object_type, bool visible);

	/**
	 * Handles a customization of chatbar width.
	 *
	 * When chatbar gets wider layout stack will reduce chiclet panel (it is auto-resizable)
	 *	But once chiclet panel reaches its minimal width Stack will force to reduce buttons width.
	 *	including Speak button. The similar behavior is when chatbar gets narrowly.
	 * This methods force resize behavior to resize buttons properly in these cases.
	 */
	void processChatbarCustomization(S32 new_width);

	/// Get button name for debugging.
	static std::string resizeStateToString(EResizeState state);

	/// Buttons automatically hidden due to lack of space.
	MASK mResizeState;

	/**
	 * Mapping of button types to the layout panels the buttons are wrapped in.
	 *
	 * Used by getButtonPanel().
	 */
	typedef std::map<EResizeState, LLPanel*> state_object_map_t;
	state_object_map_t mStateProcessedObjectMap;

	/// Default (maximum) widths of the layout panels.
	typedef std::map<EResizeState, S32> state_object_width_map_t;
	state_object_width_map_t mObjectDefaultWidthMap;

	typedef std::vector<EResizeState> resize_state_vec_t;

	/**
	 * Contains order in which child buttons should be processed in show/hide, extend/shrink methods.
	 */
	resize_state_vec_t mButtonsProcessOrder;

	/**
	 * Contains order in which child buttons are shown.
	 * It traces order of all bottomtray buttons that may change place via drag'n'drop and should
	 * save and load it between sessions. mButtonsProcessOrder is not enough for it because it contains only
	 * buttons that may be hidden.
	 */
	resize_state_vec_t mButtonsOrder;

protected:

	LLBottomTray(const LLSD& key = LLSD());

	static void* createNearbyChatBar(void* userdata);

	void updateContextMenu(S32 x, S32 y, MASK mask);
	void onContextMenuItemClicked(const LLSD& userdata);
	bool onContextMenuItemEnabled(const LLSD& userdata);

	// Either default or saved after user's manual resize width of nearby chat.
	// Nearby chat will not always have it, because sometimes it can be shrunk on resize,
	// but when possible it will be restored back to this value.
	S32					mDesiredNearbyChatWidth;
	LLChicletPanel* 	mChicletPanel;
	LLPanel*			mSpeakPanel;
	LLSpeakButton* 		mSpeakBtn;
	LLNearbyChatBar*	mNearbyChatBar;
	LLLayoutPanel*		mChatBarContainer;
	LLPanel*		mNearbyCharResizeHandlePanel;
	LLLayoutStack*		mToolbarStack;
	LLMenuGL*			mBottomTrayContextMenu;
	LLButton*			mCamButton;
	LLButton*			mMovementButton;
	LLBottomTrayLite*   mBottomTrayLite;
	bool                mIsInLiteMode;

	// Drag'n'Drop

	/**
	 * Is true if mouse down happened on draggable button.
	 * Set false whether on drag start or on mouse up.
	 */
	bool mCheckForDrag;
	/**
	 * These two variables hold corrdinates of mouse down on draggable button.
	 * They are used to compare with current coordinates of cursor and determine whether drag'n'drop should start.
	 */
	S32 mStartX;
	S32 mStartY;
	/**
	 * True if drag'n'drop is happening.
	 */
	bool mDragStarted;

	/**
	 * Pointer to panel which is currently dragged (though it seems to user that button is dragged,
	 * we are changing place of layout panel).
	 */
	LLPanel* mDraggedItem;
	/**
	 * Panel before which the dragged button will be inserted.
	 */
	LLPanel* mLandingTab;
	/**
	 * Image used to show position where dragged button will be dropped.
	 */
	LLUIImage* mImageDragIndication;

	// We want only one LLNearbyChatBarListener object, so it's tied to this singleton
	boost::shared_ptr<LLNearbyChatBarListener> mListener;
};

#endif // LL_LLBOTTOMPANEL_H