PageRenderTime 43ms CodeModel.GetById 13ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/lldockcontrol.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 378 lines | 287 code | 49 blank | 42 comment | 55 complexity | f7c272215b63bbe6fd53e3089a7a54d1 MD5 | raw file
  1/** 
  2 * @file lldockcontrol.cpp
  3 * @brief Creates a panel of a specific kind for a toast
  4 *
  5 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28
 29#include "lldockcontrol.h"
 30#include "lldockablefloater.h"
 31
 32LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
 33		const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) :
 34		mDockWidget(dockWidget),
 35		mDockableFloater(dockableFloater),
 36		mDockTongue(dockTongue),
 37		mDockTongueX(0),
 38		mDockTongueY(0)
 39{
 40	mDockAt = dockAt;
 41
 42	if (dockableFloater->isDocked())
 43	{
 44		on();
 45	}
 46	else
 47	{
 48		off();
 49	}
 50
 51	if (!(get_allowed_rect_callback))
 52	{
 53		mGetAllowedRectCallback = boost::bind(&LLDockControl::getAllowedRect, this, _1);
 54	}
 55	else
 56	{
 57		mGetAllowedRectCallback = get_allowed_rect_callback;
 58	}
 59
 60	if (dockWidget != NULL) 
 61	{
 62		repositionDockable();
 63	}
 64
 65	if (mDockWidget != NULL)
 66	{
 67		mDockWidgetVisible = isDockVisible();
 68	}
 69	else
 70	{
 71		mDockWidgetVisible = false;
 72	}
 73}
 74
 75LLDockControl::~LLDockControl()
 76{
 77}
 78
 79void LLDockControl::setDock(LLView* dockWidget)
 80{
 81	mDockWidget = dockWidget;
 82	if (mDockWidget != NULL)
 83	{
 84		repositionDockable();
 85		mDockWidgetVisible = isDockVisible();
 86	}
 87	else
 88	{
 89		mDockWidgetVisible = false;
 90	}
 91}
 92
 93void LLDockControl::getAllowedRect(LLRect& rect)
 94{
 95	rect = mDockableFloater->getRootView()->getChild<LLView>("non_toolbar_panel")->getRect();
 96}
 97
 98void LLDockControl::repositionDockable()
 99{
100	if (!mDockWidget) return;
101	LLRect dockRect = mDockWidget->calcScreenRect();
102	LLRect rootRect;
103	LLRect floater_rect = mDockableFloater->calcScreenRect();
104	mGetAllowedRectCallback(rootRect);
105
106	// recalculate dockable position if:
107	if (mPrevDockRect != dockRect					//dock position   changed
108		|| mDockWidgetVisible != isDockVisible()	//dock visibility changed
109		|| mRootRect != rootRect					//root view rect  changed
110		|| mFloaterRect != floater_rect				//floater rect    changed
111		|| mRecalculateDockablePosition				//recalculation is forced
112	)
113	{
114		// undock dockable and off() if dock not visible
115		if (!isDockVisible())
116		{
117			mDockableFloater->setDocked(false);
118			// force off() since dockable may not have dockControll at this time
119			off();
120			LLDockableFloater* dockable_floater =
121					dynamic_cast<LLDockableFloater*> (mDockableFloater);
122			if(dockable_floater != NULL)
123			{
124				dockable_floater->onDockHidden();
125			}
126		}
127		else
128		{
129			if(mEnabled)
130			{
131				moveDockable();
132			}
133			LLDockableFloater* dockable_floater =
134					dynamic_cast<LLDockableFloater*> (mDockableFloater);
135			if(dockable_floater != NULL)
136			{
137				dockable_floater->onDockShown();
138			}
139		}
140
141		mPrevDockRect = dockRect;
142		mRootRect = rootRect;
143		mFloaterRect = floater_rect;
144		mRecalculateDockablePosition = false;
145		mDockWidgetVisible = isDockVisible();
146	}
147}
148
149bool LLDockControl::isDockVisible()
150{
151	bool res = true;
152
153	if (mDockWidget != NULL)
154	{
155		//we should check all hierarchy
156		res = mDockWidget->isInVisibleChain();
157		if (res)
158		{
159			LLRect dockRect = mDockWidget->calcScreenRect();
160
161			switch (mDockAt)
162			{
163			case LEFT: // to keep compiler happy
164				break;
165			case BOTTOM:
166			case TOP:
167			{
168				// check is dock inside parent rect
169				// assume that parent for all dockable floaters
170				// is the root view
171				LLRect dockParentRect =
172						mDockWidget->getRootView()->calcScreenRect();
173				if (dockRect.mRight <= dockParentRect.mLeft
174						|| dockRect.mLeft >= dockParentRect.mRight)
175				{
176					res = false;
177				}
178				break;
179			}
180			default:
181				break;
182			}
183		}
184	}
185
186	return res;
187}
188
189void LLDockControl::moveDockable()
190{
191	// calculate new dockable position
192	LLRect dockRect = mDockWidget->calcScreenRect();
193	LLRect rootRect;
194	mGetAllowedRectCallback(rootRect);
195
196	bool use_tongue = false;
197	LLDockableFloater* dockable_floater =
198			dynamic_cast<LLDockableFloater*> (mDockableFloater);
199	if (dockable_floater != NULL)
200	{
201		use_tongue = dockable_floater->getUseTongue();
202	}
203
204	LLRect dockableRect = mDockableFloater->calcScreenRect();
205	S32 x = 0;
206	S32 y = 0;
207	LLRect dockParentRect;
208	switch (mDockAt)
209	{
210	case LEFT:
211
212		x = dockRect.mLeft - dockableRect.getWidth();
213		y = dockRect.getCenterY() + dockableRect.getHeight() / 2;
214		
215		if (use_tongue)
216		{
217			x -= mDockTongue->getWidth();
218		}
219
220		mDockTongueX = dockableRect.mRight;
221		mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2;
222		
223		break;
224
225	case RIGHT:
226
227		x = dockRect.mRight;
228		y = dockRect.getCenterY() + dockableRect.getHeight() / 2;
229
230		if (use_tongue)
231		{
232			x += mDockTongue->getWidth();
233		}
234
235		mDockTongueX = dockRect.mRight;
236		mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2;
237
238		break;
239
240	case TOP:
241		x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
242		y = dockRect.mTop + dockableRect.getHeight();
243		// unique docking used with dock tongue, so add tongue height to the Y coordinate
244		if (use_tongue)
245		{
246			y += mDockTongue->getHeight();
247
248			if ( y > rootRect.mTop)
249			{
250				y = rootRect.mTop;
251			}
252		}
253
254		// check is dockable inside root view rect
255		if (x < rootRect.mLeft)
256		{
257			x = rootRect.mLeft;
258		}
259		if (x + dockableRect.getWidth() > rootRect.mRight)
260		{
261			x = rootRect.mRight - dockableRect.getWidth();
262		}
263
264
265		// calculate dock tongue position
266		dockParentRect = mDockWidget->getParent()->calcScreenRect();
267		if (dockRect.getCenterX() < dockParentRect.mLeft)
268		{
269			mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2;
270		}
271		else if (dockRect.getCenterX() > dockParentRect.mRight)
272		{
273			mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;;
274		}
275		else
276		{
277			mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2;
278		}
279		mDockTongueY = dockRect.mTop;
280
281		break;
282	case BOTTOM:
283		x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
284		y = dockRect.mBottom;
285		// unique docking used with dock tongue, so add tongue height to the Y coordinate
286		if (use_tongue)
287		{
288			y -= mDockTongue->getHeight();
289		}
290
291		// check is dockable inside root view rect
292		if (x < rootRect.mLeft)
293		{
294			x = rootRect.mLeft;
295		}
296		if (x + dockableRect.getWidth() > rootRect.mRight)
297		{
298			x = rootRect.mRight - dockableRect.getWidth();
299		}
300
301		// calculate dock tongue position
302		dockParentRect = mDockWidget->getParent()->calcScreenRect();
303		if (dockRect.getCenterX() < dockParentRect.mLeft)
304		{
305			mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2;
306		}
307		else if (dockRect.getCenterX() > dockParentRect.mRight)
308		{
309			mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;;
310		}
311		else
312		{
313			mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2;
314		}
315		mDockTongueY = dockRect.mBottom - mDockTongue->getHeight();
316
317		break;
318	}
319
320	S32 max_available_height = rootRect.getHeight() - (rootRect.mBottom -  mDockTongueY) - mDockTongue->getHeight();
321
322	// A floater should be shrunk so it doesn't cover a part of its docking tongue and
323	// there is a space between a dockable floater and a control to which it is docked.
324	if (use_tongue && dockableRect.getHeight() >= max_available_height)
325	{
326		dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), max_available_height);
327		mDockableFloater->reshape(dockableRect.getWidth(), dockableRect.getHeight());
328	}
329	else
330	{
331		// move dockable
332		dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
333				dockableRect.getHeight());
334	}
335
336	LLRect localDocableParentRect;
337
338	mDockableFloater->getParent()->screenRectToLocal(dockableRect, &localDocableParentRect);
339	mDockableFloater->setRect(localDocableParentRect);
340	mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, &mDockTongueX, &mDockTongueY);
341
342}
343
344void LLDockControl::on()
345{
346	 if (isDockVisible())
347	{
348		mEnabled = true;
349		mRecalculateDockablePosition = true;
350	}
351}
352
353void LLDockControl::off()
354{
355	mEnabled = false;
356}
357
358void LLDockControl::forceRecalculatePosition()
359{
360	mRecalculateDockablePosition = true;
361}
362
363void LLDockControl::drawToungue()
364{
365	bool use_tongue = false;
366	LLDockableFloater* dockable_floater =
367			dynamic_cast<LLDockableFloater*> (mDockableFloater);
368	if (dockable_floater != NULL)
369	{
370		use_tongue = dockable_floater->getUseTongue();
371	}
372
373	if (mEnabled && use_tongue)
374	{
375		mDockTongue->draw(mDockTongueX, mDockTongueY);
376	}
377}
378