Пример #1
0
void PieMenu::draw( void )
{
	// save the current OpenGL drawing matrix so we can freely modify it
	gGL.pushMatrix();

	// save the widget's rectangle for later use
	LLRect r=getRect();

	// initialize pie scale factor for popup effect
	F32 factor=1.0;

#if PIE_POPUP_EFFECT
	// set the popup size if this was the first click on the menu
	if(mFirstClick)
	{
		factor=PIE_POPUP_FACTOR;
	}
	// otherwise check if the popup timer is still running
	else if(mPopupTimer.getStarted())
	{
		// if the timer ran past the popup time, stop the timer and set the size to 1.0
		F32 elapsedTime=mPopupTimer.getElapsedTimeF32();
		if(elapsedTime>PIE_POPUP_TIME)
		{
			factor=1.0;
			mPopupTimer.stop();
		}
		// otherwise calculate the size factor to make the menu shrink over time
		else
		{
			factor=PIE_POPUP_FACTOR-(PIE_POPUP_FACTOR-1.0)*elapsedTime/PIE_POPUP_TIME;
		}
//		setRect(r);  // obsolete?
	}
#endif

#if PIE_DRAW_BOUNDING_BOX
	// draw a bounding box around the menu for debugging purposes
	gl_rect_2d(0,r.getHeight(),r.getWidth(),0,LLColor4(1,1,1,1),FALSE);
#endif

	// set up pie menu colors
	LLColor4 lineColor=LLUIColorTable::instance().getColor("PieMenuLineColor");
	LLColor4 selectedColor=LLUIColorTable::instance().getColor("PieMenuSelectedColor");
	LLColor4 textColor=LLUIColorTable::instance().getColor("PieMenuTextColor");
	LLColor4 bgColor=LLUIColorTable::instance().getColor("PieMenuBgColor");
	LLColor4 borderColor=bgColor % (F32)0.3;

	// if the user wants their own colors, apply them here
	if(gSavedSettings.getBOOL("OverridePieColors"))
	{
		bgColor=LLUIColorTable::instance().getColor("PieMenuBgColorOverride") % gSavedSettings.getF32("PieMenuOpacity");
		borderColor=bgColor % (1.f-gSavedSettings.getF32("PieMenuFade"));
		selectedColor=LLUIColorTable::instance().getColor("PieMenuSelectedColorOverride");
	}

	// on first click, make the menu fade out to indicate "borderless" operation
	if(mFirstClick)
		borderColor%=0.0;

	// initially, the current segment is marked as invalid
	S32 currentSegment=-1;

	// get the current mouse pointer position local to the pie
	S32 x,y;
	LLUI::getMousePositionLocal(this,&x,&y);
	// remember to take the UI scaling into account
	LLVector2 scale=gViewerWindow->getDisplayScale();
	// move mouse coordinates to be relative to the pie center
	LLVector2 mouseVector(x-PIE_OUTER_SIZE/scale.mV[VX],y-PIE_OUTER_SIZE/scale.mV[VY]);

	// get the distance from the center point
	F32 distance=mouseVector.length();
	// check if our mouse pointer is within the pie slice area
	if(distance>PIE_INNER_SIZE && (distance<(PIE_OUTER_SIZE*factor) || mFirstClick))
	{
		// get the angle of the mouse pointer from the center in radians
		F32 angle=acos(mouseVector.mV[VX]/distance);
		// if the mouse is below the middle of the pie, reverse the angle
		if(mouseVector.mV[VY]<0)
			angle=F_PI*2-angle;
		// rotate the angle slightly so the slices' centers are aligned correctly
		angle+=F_PI/8;

		// calculate slice number from the angle
		currentSegment=(S32) (8.0*angle/(F_PI*2.0)) % 8;
	}

	// move origin point to the center of our rectangle
	gGL.translatef(r.getWidth()/2,r.getHeight()/2,0.0);

	// draw the general pie background
	gl_washer_2d(PIE_OUTER_SIZE*factor,PIE_INNER_SIZE,32,bgColor,borderColor);

	// set up an item list iterator to point at the beginning of the item list
	slice_list_t::iterator cur_item_iter;
	cur_item_iter=mSlices->begin();

	// clear current slice pointer
	mSlice=0;
	// current slice number is 0
	S32 num=0;
	BOOL wasAutohide=FALSE;
	do
	{
		// standard item text color
		LLColor4 itemColor=textColor;

		// clear the label and set up the starting angle to draw in
		std::string label("");
		F32 segmentStart=F_PI/4.0*(F32) num-F_PI/8.0;

		// iterate through the list of slices
		if(cur_item_iter!=mSlices->end())
		{
			// get current slice item
			LLView* item=(*cur_item_iter);

			// check if this is a submenu or a normal click slice
			PieSlice* currentSlice=dynamic_cast<PieSlice*>(item);
			PieMenu* currentSubmenu=dynamic_cast<PieMenu*>(item);
			// advance internally to the next slice item
			cur_item_iter++;

			// in case it is regular click slice
			if(currentSlice)
			{
				// get the slice label and tell the slice to check if it's supposed to be visible
				label=currentSlice->getLabel();
				currentSlice->updateVisible();
				// disable it if it's not visible, pie slices never really disappear
				if(!currentSlice->getVisible())
				{
					lldebugs << label << " is not visible" << llendl;
					currentSlice->setEnabled(FALSE);
				}

				// if the current slice is the start of an autohide chain, clear out previous chains
				if(currentSlice->getStartAutohide())
					wasAutohide=FALSE;

				// check if the current slice is part of an autohide chain
				if(currentSlice->getAutohide())
				{
					// if the previous item already won the autohide, skip this item
					if(wasAutohide)
						continue;
					// look at the next item in the pie
					LLView* lookAhead=(*cur_item_iter);
					// check if this is a normal click slice
					PieSlice* lookSlice=dynamic_cast<PieSlice*>(lookAhead);
					if(lookSlice)
					{
						// if the next item is part of the current autohide chain as well ...
						if(lookSlice->getAutohide() && !lookSlice->getStartAutohide())
						{
							// ... it's visible and it's enabled, skip the current one.
							// the first visible and enabled item in autohide chains wins
							// this is useful for Sit/Stand toggles
							lookSlice->updateEnabled();
							lookSlice->updateVisible();
							if(lookSlice->getVisible() && lookSlice->getEnabled())
								continue;
							// this item won the autohide contest
							wasAutohide=TRUE;
						}
					}
				}
				else
					// reset autohide chain
					wasAutohide=FALSE;
				// check if the slice is currently enabled
				currentSlice->updateEnabled();
				if(!currentSlice->getEnabled())
				{
					lldebugs << label << " is disabled" << llendl;
					// fade the item color alpha to mark the item as disabled
					itemColor%=(F32)0.3;
				}
			}
			// if it's a submenu just get the label
			else if(currentSubmenu)
				label=currentSubmenu->getLabel();

			// if it's a slice or submenu, the mouse pointer is over the same segment as our counter and the item is enabled
			if((currentSlice || currentSubmenu) && (currentSegment==num) && item->getEnabled())
			{
				// memorize the currently highlighted slice for later
				mSlice=item;
				// if we highlighted a different slice than before, we must play a sound
				if(mOldSlice!=mSlice)
				{
					// get the appropriate UI sound and play it
					char soundNum='0'+num;
					std::string soundName="UISndPieMenuSliceHighlight";
					soundName+=soundNum;

					make_ui_sound(soundName.c_str());
					// remember which slice we highlighted last, so we only play the sound once
					mOldSlice=mSlice;
				}

				// draw the currently highlighted pie slice
				gl_washer_segment_2d(PIE_OUTER_SIZE*factor,PIE_INNER_SIZE,segmentStart+0.02,segmentStart+F_PI/4.0-0.02,4,selectedColor,borderColor);
			}
		}
		// draw the divider line for this slice
		gl_washer_segment_2d(PIE_OUTER_SIZE*factor,PIE_INNER_SIZE,segmentStart-0.02,segmentStart+0.02,4,lineColor,borderColor);

		// draw the slice labels around the center
		mFont->renderUTF8(label,
							0,
							PIE_X[num],
							PIE_Y[num],
							itemColor,
							LLFontGL::HCENTER,
							LLFontGL::VCENTER,
							LLFontGL::NORMAL,
							LLFontGL::DROP_SHADOW_SOFT);
		// next slice
		num++;
	}
	while(num<8);	// do this until the menu is full

	// draw inner and outer circle, outer only if it was not the first click
	if(!mFirstClick)
		gl_washer_2d(PIE_OUTER_SIZE*factor,PIE_OUTER_SIZE*factor-2,32,lineColor,borderColor);
	gl_washer_2d(PIE_INNER_SIZE+1,PIE_INNER_SIZE-1,16,borderColor,lineColor);

	// restore OpenGL drawing matrix
	gGL.popMatrix();

	// give control back to the UI library
	LLView::draw();
}
void PieMenu::draw()
{
	// save the current OpenGL drawing matrix so we can freely modify it
	gGL.pushMatrix();

	// save the widget's rectangle for later use
	LLRect r = getRect();

	// initialize pie scale factor for popup effect
	F32 factor = getScaleFactor();

#if PIE_DRAW_BOUNDING_BOX
	// draw a bounding box around the menu for debugging purposes
	gl_rect_2d(0, r.getHeight(), r.getWidth(), 0, LLColor4::white, FALSE);
#endif

	// set up pie menu colors
	LLColor4 lineColor = LLUIColorTable::instance().getColor("PieMenuLineColor");
	LLColor4 selectedColor = LLUIColorTable::instance().getColor("PieMenuSelectedColor");
	LLColor4 textColor = LLUIColorTable::instance().getColor("PieMenuTextColor");
	LLColor4 bgColor = LLUIColorTable::instance().getColor("PieMenuBgColor");
	LLColor4 borderColor = bgColor % 0.3f;

	// if the user wants their own colors, apply them here
	static LLCachedControl<bool> sOverridePieColors(gSavedSettings, "OverridePieColors", false);
	if (sOverridePieColors)
	{
		static LLCachedControl<F32> sPieMenuOpacity(gSavedSettings, "PieMenuOpacity");
		static LLCachedControl<F32> sPieMenuFade(gSavedSettings, "PieMenuFade");
		bgColor = LLUIColorTable::instance().getColor("PieMenuBgColorOverride") % sPieMenuOpacity;
		borderColor = bgColor % (1.f - sPieMenuFade);
		selectedColor = LLUIColorTable::instance().getColor("PieMenuSelectedColorOverride");
	}

	// on first click, make the menu fade out to indicate "borderless" operation
	if (mFirstClick)
	{
		borderColor %= 0.f;
	}

	// move origin point to the center of our rectangle
	gGL.translatef(r.getWidth() / 2, r.getHeight() / 2, 0);

	// draw the general pie background
	gl_washer_2d(PIE_OUTER_SIZE * factor, PIE_INNER_SIZE, 32, bgColor, borderColor);

	// set up an item list iterator to point at the beginning of the item list
	slice_list_t::iterator cur_item_iter;
	cur_item_iter = mSlices->begin();

	// clear current slice pointer
	mSlice = NULL;
	// current slice number is 0
	S32 num = 0;
	bool wasAutohide = false;
	do
	{
		// standard item text color
		LLColor4 itemColor = textColor;

		// clear the label and set up the starting angle to draw in
		std::string label("");
		F32 segmentStart = F_PI / 4.f * (F32)num - F_PI / 8.f;

		// iterate through the list of slices
		if (cur_item_iter != mSlices->end())
		{
			// get current slice item
			LLView* item = (*cur_item_iter);

			// check if this is a submenu or a normal click slice
			PieSlice* currentSlice = dynamic_cast<PieSlice*>(item);
			PieMenu* currentSubmenu = dynamic_cast<PieMenu*>(item);
			// advance internally to the next slice item
			cur_item_iter++;

			// in case it is regular click slice
			if (currentSlice)
			{
				// get the slice label and tell the slice to check if it's supposed to be visible
				label = currentSlice->getLabel();
				currentSlice->updateVisible();
				// disable it if it's not visible, pie slices never really disappear
				BOOL slice_visible = currentSlice->getVisible();
				currentSlice->setEnabled(slice_visible);
				if (!slice_visible)
				{
				//	LL_DEBUGS() << label << " is not visible" << LL_ENDL;
					label = "";
				}

				// if the current slice is the start of an autohide chain, clear out previous chains
				if (currentSlice->getStartAutohide())
				{
					wasAutohide = false;
				}

				// check if the current slice is part of an autohide chain
				if (currentSlice->getAutohide())
				{
					// if the previous item already won the autohide, skip this item
					if (wasAutohide)
					{
						continue;
					}

					// look at the next item in the pie
					LLView* lookAhead = (*cur_item_iter);
					// check if this is a normal click slice
					PieSlice* lookSlice = dynamic_cast<PieSlice*>(lookAhead);
					if (lookSlice)
					{
						// if the next item is part of the current autohide chain as well ...
						if (lookSlice->getAutohide() && !lookSlice->getStartAutohide())
						{
							// ... it's visible and it's enabled, skip the current one.
							// the first visible and enabled item in autohide chains wins
							// this is useful for Sit/Stand toggles
							lookSlice->updateEnabled();
							lookSlice->updateVisible();
							if (lookSlice->getVisible() && lookSlice->getEnabled())
							{
								continue;
							}

							// this item won the autohide contest
							wasAutohide = true;
						}
					}
				}
				else
				{
					// reset autohide chain
					wasAutohide = false;
				}

				// check if the slice is currently enabled
				currentSlice->updateEnabled();
				if (!currentSlice->getEnabled())
				{
					LL_DEBUGS() << label << " is disabled" << LL_ENDL;
					// fade the item color alpha to mark the item as disabled
					itemColor %= 0.3f;
				}
			}
			// if it's a submenu just get the label
			else if (currentSubmenu)
			{
				label = currentSubmenu->getLabel();
			}

			// if it's a slice or submenu, the mouse pointer is over the same segment as our counter and the item is enabled
			if ((currentSlice || currentSubmenu) && (mCurrentSegment == num) && item->getEnabled())
			{
				// memorize the currently highlighted slice for later
				mSlice = item;
				// if we highlighted a different slice than before, we must play a sound
				if (mOldSlice != mSlice)
				{
					// get the appropriate UI sound and play it
					char soundNum = '0' + num;
					std::string soundName = "UISndPieMenuSliceHighlight";
					soundName += soundNum;

					make_ui_sound(soundName.c_str());
					// remember which slice we highlighted last, so we only play the sound once
					mOldSlice = mSlice;
				}

				// draw the currently highlighted pie slice
				gl_washer_segment_2d(PIE_OUTER_SIZE * factor, PIE_INNER_SIZE, segmentStart + 0.02f, segmentStart + F_PI / 4.f - 0.02f, 4, selectedColor, borderColor);
			}
		}
		// draw the divider line for this slice
		gl_washer_segment_2d(PIE_OUTER_SIZE * factor, PIE_INNER_SIZE, segmentStart - 0.02f, segmentStart + 0.02f, 4, lineColor, borderColor);

		// draw the slice labels around the center
		mFont->renderUTF8(label,
							0,
							PIE_X[num],
							PIE_Y[num],
							itemColor,
							LLFontGL::HCENTER,
							LLFontGL::VCENTER,
							LLFontGL::NORMAL,
							LLFontGL::DROP_SHADOW_SOFT);
		// next slice
		num++;
	}
	while (num < 8);	// do this until the menu is full

	// draw inner and outer circle, outer only if it was not the first click
	if (!mFirstClick)
	{
		gl_washer_2d(PIE_OUTER_SIZE * factor, PIE_OUTER_SIZE * factor - 2.f, 32, lineColor, borderColor);
	}
	gl_washer_2d(PIE_INNER_SIZE + 1, PIE_INNER_SIZE - 1, 16, borderColor, lineColor);

	// restore OpenGL drawing matrix
	gGL.popMatrix();

	// give control back to the UI library
	LLView::draw();
}