Extend autohide pie menu function to also work with sub menus and not only slices

master
Ansariel 2024-09-20 13:16:45 +02:00
parent 4646b6dd4a
commit 298f16b235
7 changed files with 190 additions and 83 deletions

View File

@ -845,6 +845,7 @@ set(viewer_SOURCE_FILES
noise.cpp
particleeditor.cpp
permissionstracker.cpp
pieautohide.cpp
piemenu.cpp
pieseparator.cpp
pieslice.cpp
@ -1646,6 +1647,7 @@ set(viewer_HEADER_FILES
noise.h
particleeditor.h
permissionstracker.h
pieautohide.h
piemenu.h
pieseparator.h
pieslice.h

View File

@ -0,0 +1,45 @@
/**
* @file pieautohide.cpp
* @brief Pie menu autohide base class
*
* $LicenseInfo:firstyear=2024&license=fsviewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2024, The Phoenix Firestorm Project, 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
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "pieautohide.h"
PieAutohide::PieAutohide(bool autohide, bool startAutohide) : mAutohide(autohide), mStartAutohide(startAutohide) {}
// accessor
bool PieAutohide::getStartAutohide() const
{
return mStartAutohide;
}
// accessor
bool PieAutohide::getAutohide() const
{
return mStartAutohide || mAutohide;
}

View File

@ -0,0 +1,48 @@
/**
* @file pieautohide.h
* @brief Pie menu autohide base class
*
* $LicenseInfo:firstyear=2024&license=fsviewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2024, The Phoenix Firestorm Project, 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
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
#ifndef PIEAUTOHIDE_H
#define PIEAUTOHIDE_H
#include "lluictrl.h"
// A slice in the pie that supports the auto-hide function.
class PieAutohide
{
public:
PieAutohide(bool autohide, bool startAutohide);
// accessor to expose the autohide feature
bool getStartAutohide() const;
bool getAutohide() const;
protected:
bool mStartAutohide{ false };
bool mAutohide{ false };
};
#endif // PIEAUTOHIDE_H

View File

@ -56,8 +56,9 @@ constexpr F32 PIE_OUTER_SHADE_FACTOR = 1.09f; // size factor of the outer shad
constexpr F32 PIE_SLICE_DIVIDER_WIDTH = 0.04f; // width of a slice divider in radians
constexpr F32 PIE_MAX_SLICES_F = F32(PIE_MAX_SLICES);
PieMenu::PieMenu(const LLMenuGL::Params& p) :
PieMenu::PieMenu(const Params& p) :
LLMenuGL(p),
PieAutohide(p.autohide, p.start_autohide),
mCurrentSegment(-1),
mOldSlice(nullptr),
mSlice(nullptr),
@ -305,22 +306,21 @@ void PieMenu::draw()
gl_washer_2d(PIE_OUTER_SIZE * factor, PIE_INNER_SIZE, steps, 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();
slice_list_t::iterator cur_item_iter{ mSlices->begin() };
// clear current slice pointer
mSlice = nullptr;
// current slice number is 0
S32 num = 0;
bool wasAutohide = false;
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("");
std::string label{ "" };
F32 segmentStart = F_PI / (PIE_MAX_SLICES_F / 2.f) * (F32)num - F_PI / PIE_MAX_SLICES_F;
// iterate through the list of slices
@ -328,16 +328,76 @@ void PieMenu::draw()
{
// 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++;
bool isSliceOrSubmenu{ false };
auto checkAutohide = [&](PieAutohide* autohideSlice)
{
// if the current slice is the start of an autohide chain, clear out previous chains
if (autohideSlice->getStartAutohide())
{
wasAutohide = false;
}
// check if the current slice is part of an autohide chain
if (autohideSlice->getAutohide())
{
// if the previous item already won the autohide, skip this item
if (wasAutohide)
{
return true;
}
// look at the next item in the pie
LLView* lookAhead = (*cur_item_iter);
// check if this is a normal click slice
if (PieSlice* lookSlice = dynamic_cast<PieSlice*>(lookAhead))
{
// 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())
{
return true;
}
// this item won the autohide contest
wasAutohide = true;
}
}
else if (PieMenu* lookSlice = dynamic_cast<PieMenu*>(lookAhead))
{
if (lookSlice->getAutohide() && !lookSlice->getStartAutohide())
{
if (/*lookSlice->getVisible() &&*/ lookSlice->getEnabled()) // Menu is somehow always set to not visible...
{
return true;
}
// this item won the autohide contest
wasAutohide = true;
}
}
}
else
{
// reset autohide chain
wasAutohide = false;
}
return false;
};
// in case it is regular click slice
if (currentSlice)
if (PieSlice* currentSlice = dynamic_cast<PieSlice*>(item))
{
isSliceOrSubmenu = true;
// get the slice label and tell the slice to check if it's supposed to be visible
label = currentSlice->getLabel();
currentSlice->updateVisible();
@ -350,50 +410,8 @@ void PieMenu::draw()
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;
}
if (checkAutohide(currentSlice))
continue;
// check if the slice is currently enabled
currentSlice->updateEnabled();
@ -404,9 +422,14 @@ void PieMenu::draw()
itemColor %= 0.3f;
}
}
// if it's a submenu just get the label
else if (currentSubmenu)
// if it's a submenu
else if (PieMenu* currentSubmenu = dynamic_cast<PieMenu*>(item))
{
isSliceOrSubmenu = true;
if (checkAutohide(currentSubmenu))
continue;
label = currentSubmenu->getLabel();
if (sPieMenuOuterRingShade)
{
@ -415,7 +438,7 @@ void PieMenu::draw()
}
// 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())
if (isSliceOrSubmenu && (mCurrentSegment == num) && item->getEnabled())
{
// memorize the currently highlighted slice for later
mSlice = item;

View File

@ -30,6 +30,7 @@
#include "llmenugl.h"
#include "llframetimer.h"
#include "pieautohide.h"
constexpr S32 PIE_MAX_SLICES = 8;
@ -39,15 +40,21 @@ struct PieChildRegistry : public LLChildRegistry<PieChildRegistry>
LLSINGLETON_EMPTY_CTOR(PieChildRegistry);
};
class PieMenu : public LLMenuGL
class PieMenu : public LLMenuGL, public PieAutohide
{
public:
// parameter block for the XUI factory
struct Params : public LLInitParam::Block<Params, LLMenuGL::Params>
{
Optional<std::string> name;
// autohide feature to hide a disabled pie slice
Optional<bool> start_autohide;
// next item in an autohide chain
Optional<bool> autohide;
Params()
Params() :
start_autohide("start_autohide", false),
autohide("autohide", false)
{
visible = false;
}
@ -56,7 +63,7 @@ public:
// PieChildRegistry contains a list of allowed child types for the XUI definition
typedef PieChildRegistry child_registry_t;
PieMenu(const LLMenuGL::Params& p);
PieMenu(const Params& p);
/*virtual*/ void setVisible(bool visible);

View File

@ -43,9 +43,8 @@ PieSlice::Params::Params() :
// create a new slice and memorize the XUI parameters
PieSlice::PieSlice(const PieSlice::Params& p) :
LLUICtrl(p),
PieAutohide(p.autohide, p.start_autohide),
mLabel(p.label),
mStartAutohide(p.start_autohide),
mAutohide(p.autohide),
mCheckEnableOnce(p.check_enable_once),
mDoUpdateEnabled(true)
{
@ -140,18 +139,6 @@ void PieSlice::setLabel(std::string_view newLabel)
mLabel = newLabel;
}
// accessor
bool PieSlice::getStartAutohide() const
{
return mStartAutohide;
}
// accessor
bool PieSlice::getAutohide() const
{
return mStartAutohide || mAutohide;
}
void PieSlice::resetUpdateEnabledCheck()
{
mDoUpdateEnabled = true;

View File

@ -29,10 +29,11 @@
#define PIESLICE_H
#include "lluictrl.h"
#include "pieautohide.h"
// A slice in the pie. Does nothing by itself, just stores the function and
// parameter to be execued when the user clicks on this item
class PieSlice : public LLUICtrl
class PieSlice : public LLUICtrl, public PieAutohide
{
public:
// parameter block for the XUI factory
@ -70,10 +71,6 @@ public:
LLSD getValue() const;
void setValue(const LLSD& value);
// accessor to expose the autohide feature
bool getStartAutohide() const;
bool getAutohide() const;
// callback connection for the onCommit method to launch the specified function
boost::signals2::connection setClickCallback(const commit_signal_t::slot_type& cb)
{
@ -91,8 +88,6 @@ public:
protected:
// accessor store
std::string mLabel;
bool mStartAutohide;
bool mAutohide;
bool mCheckEnableOnce;
bool mDoUpdateEnabled;