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(); }