Apertura del repositorio

This commit is contained in:
2025-05-24 18:09:39 -03:00
parent 76e6359dad
commit d883ddd0d0
35253 changed files with 2891973 additions and 2 deletions
+293
View File
@@ -0,0 +1,293 @@
# -*- cmake -*-
project(llui)
include(00-Common)
include(Hunspell)
include(LLCommon)
include(LLImage)
include(LLCoreHttp)
include(LLWindow)
include(LLCoreHttp)
set(llui_SOURCE_FILES
fsregistrarutils.cpp
llaccordionctrl.cpp
llaccordionctrltab.cpp
llbadge.cpp
llbadgeholder.cpp
llbadgeowner.cpp
llbutton.cpp
llchatentry.cpp
llcheckboxctrl.cpp
llclipboard.cpp
llcombobox.cpp
llcommandmanager.cpp
llconsole.cpp
llcontainerview.cpp
llctrlselectioninterface.cpp
lldockablefloater.cpp
lldockcontrol.cpp
lldraghandle.cpp
lleditmenuhandler.cpp
llemojidictionary.cpp
llemojihelper.cpp
llf32uictrl.cpp
llfiltereditor.cpp
llflashtimer.cpp
llflatlistview.cpp
llfloater.cpp
llfloaterreg.cpp
llfloaterreglistener.cpp
llflyoutbutton.cpp
llfocusmgr.cpp
llfolderview.cpp
llfolderviewitem.cpp
llfolderviewmodel.cpp
lliconctrl.cpp
llkeywords.cpp
lllayoutstack.cpp
lllineeditor.cpp
llloadingindicator.cpp
lllocalcliprect.cpp
llmenubutton.cpp
llmenugl.cpp
llmodaldialog.cpp
llmultifloater.cpp
llmultislider.cpp
llmultisliderctrl.cpp
llnotifications.cpp
llnotificationslistener.cpp
llnotificationsutil.cpp
llpanel.cpp
llprogressbar.cpp
llradiogroup.cpp
llresizebar.cpp
llresizehandle.cpp
llresmgr.cpp
llrngwriter.cpp
llscrollbar.cpp
llscrollcontainer.cpp
llscrollingpanellist.cpp
llscrolllistcell.cpp
llscrolllistcolumn.cpp
llscrolllistctrl.cpp
llscrolllistitem.cpp
llsearcheditor.cpp
llslider.cpp
llsliderctrl.cpp
llspellcheck.cpp
llspinctrl.cpp
llstatbar.cpp
llstatgraph.cpp
llstatview.cpp
llstyle.cpp
lltabcontainer.cpp
lltextbase.cpp
lltextbox.cpp
lltexteditor.cpp
lltextparser.cpp
lltextutil.cpp
lltextvalidate.cpp
lltimectrl.cpp
lltrans.cpp
lltransutil.cpp
lltoggleablemenu.cpp
lltoolbar.cpp
lltooltip.cpp
llui.cpp
lluicolor.cpp
lluicolortable.cpp
lluictrl.cpp
lluictrlfactory.cpp
lluistring.cpp
lluiusage.cpp
llundo.cpp
llurlaction.cpp
llurlentry.cpp
llurlmatch.cpp
llurlregistry.cpp
llviewborder.cpp
llviewinject.cpp
llviewmodel.cpp
llview.cpp
llviewquery.cpp
llviewereventrecorder.cpp
llvirtualtrackball.cpp
llwindowshade.cpp
llxuiparser.cpp
llxyvector.cpp
)
set(llui_HEADER_FILES
CMakeLists.txt
fsregistrarutils.h
llaccordionctrl.h
llaccordionctrltab.h
llbadge.h
llbadgeholder.h
llbadgeowner.h
llbutton.h
llcallbackmap.h
llchatentry.h
llchat.h
llcheckboxctrl.h
llclipboard.h
llcombobox.h
llcommandmanager.h
llconsole.h
llcontainerview.h
llctrlselectioninterface.h
lldraghandle.h
lldockablefloater.h
lldockcontrol.h
lleditmenuhandler.h
llemojidictionary.h
llemojihelper.h
llf32uictrl.h
llfiltereditor.h
llflashtimer.h
llflatlistview.h
llfloater.h
llfloaterreg.h
llfloaterreglistener.h
llflyoutbutton.h
llfocusmgr.h
llfolderview.h
llfolderviewitem.h
llfolderviewmodel.h
llfunctorregistry.h
llhelp.h
lliconctrl.h
llkeywords.h
lllayoutstack.h
lllazyvalue.h
lllineeditor.h
llloadingindicator.h
lllocalcliprect.h
llmenubutton.h
llmenugl.h
llmodaldialog.h
llmultifloater.h
llmultisliderctrl.h
llmultislider.h
llnotificationptr.h
llnotifications.h
llnotificationslistener.h
llnotificationsutil.h
llnotificationtemplate.h
llnotificationvisibilityrule.h
llpanel.h
llprogressbar.h
llradiogroup.h
llresizebar.h
llresizehandle.h
llresmgr.h
llrngwriter.h
llsearchablecontrol.h
llsearcheditor.h
llscrollbar.h
llscrollcontainer.h
llscrollingpanellist.h
llscrolllistcell.h
llscrolllistcolumn.h
llscrolllistctrl.h
llscrolllistitem.h
llsliderctrl.h
llslider.h
llspellcheck.h
llspellcheckmenuhandler.h
llspinctrl.h
llstatbar.h
llstatgraph.h
llstatview.h
llstyle.h
lltabcontainer.h
lltextbase.h
lltextbox.h
lltexteditor.h
lltextparser.h
lltextutil.h
lltextvalidate.h
lltimectrl.h
lltoggleablemenu.h
lltoolbar.h
lltooltip.h
lltrans.h
lltransutil.h
lluicolortable.h
lluiconstants.h
lluictrlfactory.h
lluictrl.h
lluifwd.h
llui.h
lluicolor.h
lluistring.h
lluiusage.h
llundo.h
llurlaction.h
llurlentry.h
llurlmatch.h
llurlregistry.h
llviewborder.h
llviewinject.h
llviewmodel.h
llview.h
llviewereventrecorder.h
llviewquery.h
llvirtualtrackball.h
llwindowshade.h
llxuiparser.h
llxyvector.h
)
SET(llurlentry_TEST_DEPENDENCIES
llurlmatch.cpp
llurlregistry.cpp
)
set_source_files_properties(llurlentry.cpp
PROPERTIES LL_TEST_ADDITIONAL_SOURCE_FILES
"${llurlentry_TEST_DEPENDENCIES}"
)
list(APPEND llui_SOURCE_FILES ${llui_HEADER_FILES})
add_library (llui ${llui_SOURCE_FILES})
target_include_directories( llui INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
# Libraries on which this library depends, needed for Linux builds
# Sort by high-level to low-level
target_link_libraries(llui
llrender
llwindow
llimage
llinventory
llmessage
llcorehttp
llfilesystem
llxml
llmath
ll::hunspell
llcommon
)
# Add tests
if(LL_TESTS)
include(LLAddBuildTest)
set(test_libs llmessage llcorehttp llxml llrender llcommon ll::hunspell)
SET(llui_TEST_SOURCE_FILES
llurlmatch.cpp
)
set_property( SOURCE ${llui_TEST_SOURCE_FILES} PROPERTY LL_TEST_ADDITIONAL_LIBRARIES ${test_libs})
LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}")
# INTEGRATION TESTS
if(NOT LINUX)
set(test_libs llui llmessage llcorehttp llxml llrender llcommon ll::hunspell )
LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
endif(NOT LINUX)
endif(LL_TESTS)
+40
View File
@@ -0,0 +1,40 @@
/**
* @file fsregistrarutils.cpp
* @brief Utility class to allow registrars access information from dependent projects
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (c) 2013 Ansariel Hiller @ Second Life
*
* 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 "linden_common.h"
#include "fsregistrarutils.h"
bool FSRegistrarUtils::checkIsEnabled(LLUUID av_id, EFSRegistrarFunctionActionType action)
{
if (mEnableCheckFunction)
{
return mEnableCheckFunction(av_id, action);
}
return false;
}
FSRegistrarUtils gFSRegistrarUtils;
+75
View File
@@ -0,0 +1,75 @@
/**
* @file fsregistrarutils.h
* @brief Utility class to allow registrars access information from dependent projects
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (c) 2013 Ansariel Hiller @ Second Life
*
* 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 FS_REGISTRARUTILS_H
#define FS_REGISTRARUTILS_H
#include <functional>
enum class EFSRegistrarFunctionActionType
{
FS_RGSTR_ACT_ADD_FRIEND,
FS_RGSTR_ACT_REMOVE_FRIEND,
FS_RGSTR_ACT_SEND_IM,
FS_RGSTR_ACT_VIEW_TRANSCRIPT,
FS_RGSTR_ACT_ZOOM_IN,
FS_RGSTR_ACT_OFFER_TELEPORT,
FS_RGSTR_ACT_SHOW_PROFILE,
FS_RGSTR_ACT_TRACK_AVATAR,
FS_RGSTR_ACT_TELEPORT_TO,
FS_RGSTR_ACT_REQUEST_TELEPORT,
FS_RGSTR_CHK_AVATAR_BLOCKED,
FS_RGSTR_CHK_IS_SELF,
FS_RGSTR_CHK_IS_NOT_SELF,
FS_RGSTR_CHK_WAITING_FOR_GROUP_DATA,
FS_RGSTR_CHK_HAVE_GROUP_DATA,
FS_RGSTR_CHK_CAN_LEAVE_GROUP,
FS_RGSTR_CHK_CAN_JOIN_GROUP,
FS_RGSTR_CHK_GROUP_NOT_ACTIVE
};
class FSRegistrarUtils
{
public:
FSRegistrarUtils() = default;
~FSRegistrarUtils() = default;
using enable_check_function_t = std::function<bool(const LLUUID&, EFSRegistrarFunctionActionType)>;
void setEnableCheckFunction(const enable_check_function_t& func)
{
mEnableCheckFunction = func;
}
bool checkIsEnabled(LLUUID av_id, EFSRegistrarFunctionActionType action);
private:
enable_check_function_t mEnableCheckFunction{ nullptr };
};
extern FSRegistrarUtils gFSRegistrarUtils;
#endif // FS_REGISTRARUTILS_H
+70
View File
@@ -0,0 +1,70 @@
#ifndef FS_SEARCHABLE_CONTROL_H
#define FS_SEARCHABLE_CONTROL_H
/**
* $LicenseInfo:firstyear=2014&license=fsviewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2014, Nicky Dasmijn
*
* 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 "lluicolortable.h"
#include "lluicolor.h"
namespace nd
{
namespace ui
{
class SearchableControl
{
mutable bool mIsHighlighed;
public:
SearchableControl()
: mIsHighlighed( false )
{ }
virtual ~SearchableControl()
{ }
LLColor4 getHighlightColor( ) const
{
static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red);
return highlight_color.get();
}
void setHighlighted( bool aVal ) const
{
mIsHighlighed = aVal;
onSetHighlight( );
}
bool getHighlighted( ) const
{ return mIsHighlighed; }
std::string getSearchText() const
{ return _getSearchText(); }
protected:
virtual std::string _getSearchText() const = 0;
virtual void onSetHighlight( ) const
{ }
};
}
}
#endif
+937
View File
@@ -0,0 +1,937 @@
/**
* @file llaccordionctrl.cpp
* @brief Accordion panel implementation
*
* $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$
*/
#include "linden_common.h"
#include "llaccordionctrl.h"
#include "llaccordionctrltab.h"
#include "lluictrlfactory.h" // builds floaters from XML
#include "llwindow.h"
#include "llfocusmgr.h"
#include "lllocalcliprect.h"
#include "boost/bind.hpp"
static constexpr S32 BORDER_MARGIN = 2;
static constexpr S32 PARENT_BORDER_MARGIN = 5;
static constexpr S32 VERTICAL_MULTIPLE = 16;
static constexpr F32 MIN_AUTO_SCROLL_RATE = 120.f;
static constexpr F32 MAX_AUTO_SCROLL_RATE = 500.f;
static constexpr F32 AUTO_SCROLL_RATE_ACCEL = 120.f;
// LLAccordionCtrl =================================================================|
static LLDefaultChildRegistry::Register<LLAccordionCtrl> t2("accordion");
LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params)
, mFitParent(params.fit_parent)
, mNoVisibleTabsOrigString(params.no_visible_tabs_text.initial_value().asString())
{
initNoTabsWidget(params.no_matched_tabs_text);
mSingleExpansion = params.single_expansion;
if (mFitParent && !mSingleExpansion)
{
LL_INFOS() << "fit_parent works best when combined with single_expansion" << LL_ENDL;
}
}
LLAccordionCtrl::LLAccordionCtrl() : LLPanel()
{
initNoTabsWidget(LLTextBox::Params());
mSingleExpansion = false;
mFitParent = false;
buildFromFile( "accordion_parent.xml");
}
//---------------------------------------------------------------------------------
void LLAccordionCtrl::draw()
{
if (mAutoScrolling)
{
// add acceleration to autoscroll
mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), MAX_AUTO_SCROLL_RATE);
}
else
{
// reset to minimum for next time
mAutoScrollRate = MIN_AUTO_SCROLL_RATE;
}
// clear this flag to be set on next call to autoScroll
mAutoScrolling = false;
LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
LLLocalClipRect clip(local_rect);
LLPanel::draw();
}
//---------------------------------------------------------------------------------
bool LLAccordionCtrl::postBuild()
{
static LLUICachedControl<S32> scrollbar_size("UIScrollbarSize", 0);
LLRect scroll_rect;
scroll_rect.setOriginAndSize(
getRect().getWidth() - scrollbar_size,
1,
scrollbar_size,
getRect().getHeight() - 1);
LLScrollbar::Params sbparams;
sbparams.name("scrollable vertical");
sbparams.rect(scroll_rect);
sbparams.orientation(LLScrollbar::VERTICAL);
sbparams.doc_size(mInnerRect.getHeight());
sbparams.doc_pos(0);
sbparams.page_size(mInnerRect.getHeight());
sbparams.step_size(VERTICAL_MULTIPLE);
sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
sbparams.change_callback(boost::bind(&LLAccordionCtrl::onScrollPosChangeCallback, this, _1, _2));
mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams);
LLView::addChild(mScrollbar);
mScrollbar->setVisible(false);
mScrollbar->setFollowsRight();
mScrollbar->setFollowsTop();
mScrollbar->setFollowsBottom();
//if it was created from xml...
std::vector<LLAccordionCtrlTab*> accordion_tabs;
for(LLView* viewp : *getChildList())
{
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(viewp);
if (accordion_tab == NULL)
continue;
if (std::find(mAccordionTabs.begin(), mAccordionTabs.end(), accordion_tab) == mAccordionTabs.end())
{
accordion_tabs.push_back(accordion_tab);
}
}
for (auto it = accordion_tabs.rbegin();
it < accordion_tabs.rend(); ++it)
{
addCollapsibleCtrl(*it);
}
arrange();
if (mSingleExpansion)
{
if (!mAccordionTabs[0]->getDisplayChildren())
mAccordionTabs[0]->setDisplayChildren(true);
for (size_t i = 1; i < mAccordionTabs.size(); ++i)
{
if (mAccordionTabs[i]->getDisplayChildren())
mAccordionTabs[i]->setDisplayChildren(false);
}
}
updateNoTabsHelpTextVisibility();
return true;
}
//---------------------------------------------------------------------------------
LLAccordionCtrl::~LLAccordionCtrl()
{
mAccordionTabs.clear();
}
//---------------------------------------------------------------------------------
void LLAccordionCtrl::reshape(S32 width, S32 height, bool called_from_parent)
{
// adjust our rectangle
LLRect rcLocal = getRect();
rcLocal.mRight = rcLocal.mLeft + width;
rcLocal.mTop = rcLocal.mBottom + height;
// get textbox a chance to reshape its content
mNoVisibleTabsHelpText->reshape(width, height, called_from_parent);
setRect(rcLocal);
// assume that help text is always fit accordion.
// necessary text paddings can be set via h_pad and v_pad
mNoVisibleTabsHelpText->setRect(getLocalRect());
arrange();
}
//---------------------------------------------------------------------------------
bool LLAccordionCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
return LLPanel::handleRightMouseDown(x, y, mask);
}
//---------------------------------------------------------------------------------
void LLAccordionCtrl::shiftAccordionTabs(S16 panel_num, S32 delta)
{
for (size_t i = panel_num; i < mAccordionTabs.size(); ++i)
{
ctrlShiftVertical(mAccordionTabs[i],delta);
}
}
//---------------------------------------------------------------------------------
void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num)
{
if (mSingleExpansion)
{
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
{
if (i == panel_num)
continue;
if (mAccordionTabs[i]->getDisplayChildren())
mAccordionTabs[i]->setDisplayChildren(false);
}
}
arrange();
}
void LLAccordionCtrl::show_hide_scrollbar(S32 width, S32 height)
{
calcRecuiredHeight();
if (getRecuiredHeight() > height)
showScrollbar(width, height);
else
hideScrollbar(width, height);
}
void LLAccordionCtrl::showScrollbar(S32 width, S32 height)
{
bool was_visible = mScrollbar->getVisible();
mScrollbar->setVisible(true);
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
ctrlSetLeftTopAndSize(mScrollbar
, width - scrollbar_size - PARENT_BORDER_MARGIN / 2
, height - PARENT_BORDER_MARGIN
, scrollbar_size
, height - PARENT_BORDER_MARGIN * 2);
mScrollbar->setPageSize(height);
mScrollbar->setDocParams(mInnerRect.getHeight(), mScrollbar->getDocPos());
if (was_visible)
{
S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1);
mScrollbar->setDocPos(scroll_pos);
}
}
void LLAccordionCtrl::hideScrollbar(S32 width, S32 height)
{
if (!mScrollbar->getVisible())
return;
mScrollbar->setVisible(false);
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
S32 panel_width = width - 2*BORDER_MARGIN;
// Reshape all accordions and shift all draggers
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
{
LLRect panel_rect = mAccordionTabs[i]->getRect();
ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_rect.mLeft, panel_rect.mTop, panel_width, panel_rect.getHeight());
}
mScrollbar->setDocPos(0);
if (!mAccordionTabs.empty())
{
S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel
S32 diff = panel_top - mAccordionTabs[0]->getRect().mTop;
shiftAccordionTabs(0, diff);
}
}
//---------------------------------------------------------------------------------
S32 LLAccordionCtrl::calcRecuiredHeight()
{
S32 rec_height = 0;
for(LLAccordionCtrlTab* accordion_tab : mAccordionTabs)
{
if(accordion_tab && accordion_tab->getVisible())
{
rec_height += accordion_tab->getRect().getHeight();
}
}
mInnerRect.setLeftTopAndSize(0, rec_height + BORDER_MARGIN * 2, getRect().getWidth(), rec_height + BORDER_MARGIN);
return mInnerRect.getHeight();
}
//---------------------------------------------------------------------------------
void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height)
{
if (!panel)
return;
LLRect panel_rect = panel->getRect();
panel_rect.setLeftTopAndSize( left, top, width, height);
panel->reshape( width, height, 1);
panel->setRect(panel_rect);
}
void LLAccordionCtrl::ctrlShiftVertical(LLView* panel, S32 delta)
{
if (!panel)
return;
panel->translate(0,delta);
}
//---------------------------------------------------------------------------------
// <FS:ND> If adding a lot of controls rapidly, calling arrange will cost a lot of times, as it's running through n! controls.
// In that case we can avvoid calling arrange over and over and just call it once when finished.
//void LLAccordionCtrl::addCollapsibleCtrl(LLAccordionCtrlTab* accordion_tab)
void LLAccordionCtrl::addCollapsibleCtrl(LLAccordionCtrlTab* accordion_tab, bool aArrange)
// </FS:ND>
{
if (!accordion_tab)
return;
if (std::find(beginChild(), endChild(), accordion_tab) == endChild())
addChild(accordion_tab);
mAccordionTabs.push_back(accordion_tab);
accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, (S16)(mAccordionTabs.size() - 1)) );
// <FS:ND> If adding a lot of controls rapidly, calling arrange will cost a lot of times, as it's running through n! controls.
// In that case we can avvoid calling arrange over and over and just call it once when finished.
// arrange();
if( aArrange )
arrange();
// </FS:ND>
}
void LLAccordionCtrl::removeCollapsibleCtrl(LLAccordionCtrlTab* accordion_tab)
{
if(!accordion_tab)
return;
if(std::find(beginChild(), endChild(), accordion_tab) != endChild())
removeChild(accordion_tab);
for (std::vector<LLAccordionCtrlTab*>::iterator iter = mAccordionTabs.begin();
iter != mAccordionTabs.end(); ++iter)
{
if (accordion_tab == (*iter))
{
mAccordionTabs.erase(iter);
break;
}
}
// if removed is selected - reset selection
if (mSelectedTab == accordion_tab)
{
mSelectedTab = NULL;
}
}
void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params)
{
LLTextBox::Params tp = tb_params;
tp.rect(getLocalRect());
mNoMatchedTabsOrigString = tp.initial_value().asString();
mNoVisibleTabsHelpText = LLUICtrlFactory::create<LLTextBox>(tp, this);
}
void LLAccordionCtrl::updateNoTabsHelpTextVisibility()
{
bool visible_exists{ false };
for (auto accordion_tab : mAccordionTabs)
{
if (accordion_tab->getVisible())
{
visible_exists = true;
break;
}
}
mNoVisibleTabsHelpText->setVisible(!visible_exists);
}
void LLAccordionCtrl::arrangeSingle()
{
S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
S32 panel_width = getRect().getWidth() - 4;
S32 panel_height;
S32 collapsed_height = 0;
for (LLAccordionCtrlTab* accordion_tab : mAccordionTabs)
{
if (!accordion_tab->getVisible()) // Skip hidden accordion tabs
continue;
if (!accordion_tab->isExpanded() )
{
collapsed_height += accordion_tab->getRect().getHeight();
}
}
S32 expanded_height = getRect().getHeight() - BORDER_MARGIN - collapsed_height;
for (LLAccordionCtrlTab* accordion_tab : mAccordionTabs)
{
if (!accordion_tab->getVisible()) // Skip hidden accordion tabs
continue;
if (!accordion_tab->isExpanded() )
{
panel_height = accordion_tab->getRect().getHeight();
}
else
{
if (mFitParent)
{
panel_height = expanded_height;
}
else
{
if (accordion_tab->getAccordionView())
{
panel_height = accordion_tab->getAccordionView()->getRect().getHeight() +
accordion_tab->getHeaderHeight() + BORDER_MARGIN * 2;
}
else
{
panel_height = accordion_tab->getRect().getHeight();
}
}
}
// make sure at least header is shown
panel_height = llmax(panel_height, accordion_tab->getHeaderHeight());
ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height);
panel_top -= accordion_tab->getRect().getHeight();
}
show_hide_scrollbar(getRect().getWidth(), getRect().getHeight());
updateLayout(getRect().getWidth(), getRect().getHeight());
}
void LLAccordionCtrl::arrangeMultiple()
{
S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
S32 panel_width = getRect().getWidth() - 4;
//Calculate params
for (size_t i = 0, end = mAccordionTabs.size(); i < end; i++)
{
LLAccordionCtrlTab* accordion_tab = static_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
if (!accordion_tab->getVisible()) // Skip hidden accordion tabs
continue;
if (!accordion_tab->isExpanded() )
{
ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, accordion_tab->getRect().getHeight());
panel_top -= accordion_tab->getRect().getHeight();
}
else
{
S32 panel_height = accordion_tab->getRect().getHeight();
if (mFitParent)
{
// All expanded tabs will have equal height
panel_height = calcExpandedTabHeight(static_cast<S32>(i), panel_top);
ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height);
// Try to make accordion tab fit accordion view height.
// Accordion View should implement getRequiredRect() and provide valid height
S32 optimal_height = accordion_tab->getAccordionView()->getRequiredRect().getHeight();
optimal_height += accordion_tab->getHeaderHeight() + 2 * BORDER_MARGIN;
if (optimal_height < panel_height)
{
panel_height = optimal_height;
}
// minimum tab height is equal to header height
if (accordion_tab->getHeaderHeight() > panel_height)
{
panel_height = accordion_tab->getHeaderHeight();
}
}
ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height);
panel_top -= panel_height;
}
}
show_hide_scrollbar(getRect().getWidth(), getRect().getHeight());
updateLayout(getRect().getWidth(), getRect().getHeight());
}
void LLAccordionCtrl::arrange()
{
updateNoTabsHelpTextVisibility();
if (mAccordionTabs.empty())
{
// Nothing to arrange
return;
}
if (mAccordionTabs.size() == 1)
{
S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel
S32 panel_width = getRect().getWidth() - 4;
LLAccordionCtrlTab* accordion_tab = mAccordionTabs[0];
LLRect panel_rect = accordion_tab->getRect();
S32 panel_height = getRect().getHeight() - BORDER_MARGIN * 2;
if (accordion_tab->getFitParent())
panel_height = accordion_tab->getRect().getHeight();
ctrlSetLeftTopAndSize(accordion_tab, panel_rect.mLeft, panel_top, panel_width, panel_height);
show_hide_scrollbar(getRect().getWidth(), getRect().getHeight());
return;
}
if (mSingleExpansion)
arrangeSingle();
else
arrangeMultiple();
}
//---------------------------------------------------------------------------------
bool LLAccordionCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
{
if (LLPanel::handleScrollWheel(x, y, clicks))
return true;
if (mScrollbar->getVisible() && mScrollbar->handleScrollWheel(0, 0, clicks))
return true;
return false;
}
bool LLAccordionCtrl::handleKeyHere(KEY key, MASK mask)
{
if (mScrollbar->getVisible() && mScrollbar->handleKeyHere(key, mask))
return true;
return LLPanel::handleKeyHere(key, mask);
}
bool LLAccordionCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask,
bool drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg)
{
// Scroll folder view if needed. Never accepts a drag or drop.
*accept = ACCEPT_NO;
bool handled = autoScroll(x, y);
if (!handled)
{
handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type,
cargo_data, accept, tooltip_msg) != NULL;
}
return true;
}
bool LLAccordionCtrl::autoScroll(S32 x, S32 y)
{
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
bool scrolling = false;
if (mScrollbar->getVisible())
{
LLRect rect_local(0, getRect().getHeight(), getRect().getWidth() - scrollbar_size, 0);
LLRect screen_local_extents;
// clip rect against root view
screenRectToLocal(getRootView()->getLocalRect(), &screen_local_extents);
rect_local.intersectWith(screen_local_extents);
// autoscroll region should take up no more than one third of visible scroller area
S32 auto_scroll_region_height = llmin(rect_local.getHeight() / 3, 10);
S32 auto_scroll_speed = ll_round(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32());
LLRect bottom_scroll_rect = screen_local_extents;
bottom_scroll_rect.mTop = rect_local.mBottom + auto_scroll_region_height;
if (bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() < mScrollbar->getDocPosMax()))
{
mScrollbar->setDocPos(mScrollbar->getDocPos() + auto_scroll_speed);
mAutoScrolling = true;
scrolling = true;
}
LLRect top_scroll_rect = screen_local_extents;
top_scroll_rect.mBottom = rect_local.mTop - auto_scroll_region_height;
if (top_scroll_rect.pointInRect(x, y) && (mScrollbar->getDocPos() > 0))
{
mScrollbar->setDocPos(mScrollbar->getDocPos() - auto_scroll_speed);
mAutoScrolling = true;
scrolling = true;
}
}
return scrolling;
}
void LLAccordionCtrl::updateLayout(S32 width, S32 height)
{
S32 panel_top = height - BORDER_MARGIN ;
if (mScrollbar->getVisible())
panel_top += mScrollbar->getDocPos();
S32 panel_width = width - BORDER_MARGIN * 2;
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
if (mScrollbar->getVisible())
panel_width -= scrollbar_size;
// set sizes for first panels and dragbars
for (LLAccordionCtrlTab* accordion_tab : mAccordionTabs)
{
if (!accordion_tab->getVisible())
continue;
LLRect panel_rect = accordion_tab->getRect();
ctrlSetLeftTopAndSize(accordion_tab, panel_rect.mLeft, panel_top, panel_width, panel_rect.getHeight());
panel_top -= panel_rect.getHeight();
}
}
void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*)
{
updateLayout(getRect().getWidth(), getRect().getHeight());
}
// virtual
void LLAccordionCtrl::onUpdateScrollToChild(const LLUICtrl *cntrl)
{
if (mScrollbar && mScrollbar->getVisible() && !mSkipScrollToChild)
{
// same as scrollToShowRect
LLRect rect;
cntrl->localRectToOtherView(cntrl->getLocalRect(), &rect, this);
// Translate to parent coordinatess to check if we are in visible rectangle
rect.translate(getRect().mLeft, getRect().mBottom);
if (!getRect().contains(rect))
{
// for accordition's scroll, height is in pixels
// Back to local coords and calculate position for scroller
S32 bottom = mScrollbar->getDocPos() - rect.mBottom + getRect().mBottom;
S32 top = mScrollbar->getDocPos() - rect.mTop + getRect().mTop;
S32 scroll_pos = llclamp(mScrollbar->getDocPos(),
bottom, // min vertical scroll
top); // max vertical scroll
mScrollbar->setDocPos(scroll_pos);
}
}
LLUICtrl::onUpdateScrollToChild(cntrl);
}
void LLAccordionCtrl::onOpen(const LLSD& key)
{
for (LLAccordionCtrlTab* accordion_tab : mAccordionTabs)
{
LLPanel* panel = dynamic_cast<LLPanel*>(accordion_tab->getAccordionView());
if (panel != NULL)
{
panel->onOpen(key);
}
}
}
S32 LLAccordionCtrl::notifyParent(const LLSD& info)
{
if (info.has("action"))
{
std::string str_action = info["action"];
if (str_action == "size_changes")
{
//
arrange();
return 1;
}
if (str_action == "select_next")
{
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
{
LLAccordionCtrlTab* accordion_tab = static_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
if (accordion_tab->hasFocus())
{
while (++i < mAccordionTabs.size())
{
if (mAccordionTabs[i]->getVisible())
break;
}
if (i < mAccordionTabs.size())
{
accordion_tab = static_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
accordion_tab->notify(LLSD().with("action","select_first"));
return 1;
}
break;
}
}
return 0;
}
if (str_action == "select_prev")
{
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
{
LLAccordionCtrlTab* accordion_tab = static_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
if (accordion_tab->hasFocus() && i > 0)
{
bool prev_visible_tab_found = false;
while (i > 0)
{
if (mAccordionTabs[--i]->getVisible())
{
prev_visible_tab_found = true;
break;
}
}
if (prev_visible_tab_found)
{
accordion_tab = static_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
accordion_tab->notify(LLSD().with("action","select_last"));
return 1;
}
break;
}
}
return 0;
}
if (str_action == "select_current")
{
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
{
// Set selection to the currently focused tab.
if (mAccordionTabs[i]->hasFocus())
{
if (mAccordionTabs[i] != mSelectedTab)
{
if (mSelectedTab)
{
mSelectedTab->setSelected(false);
}
mSelectedTab = mAccordionTabs[i];
mSelectedTab->setSelected(true);
}
return 1;
}
}
return 0;
}
if (str_action == "deselect_current")
{
// Reset selection to the currently selected tab.
if (mSelectedTab)
{
mSelectedTab->setSelected(false);
mSelectedTab = NULL;
return 1;
}
return 0;
}
}
else if (info.has("scrollToShowRect"))
{
LLRect screen_rc, local_rc;
screen_rc.setValue(info["scrollToShowRect"]);
screenRectToLocal(screen_rc, &local_rc);
// Translate to parent coordinatess to check if we are in visible rectangle
local_rc.translate(getRect().mLeft, getRect().mBottom);
if (!getRect().contains (local_rc))
{
// Back to local coords and calculate position for scroller
S32 bottom = mScrollbar->getDocPos() - local_rc.mBottom + getRect().mBottom;
S32 top = mScrollbar->getDocPos() - local_rc.mTop + getRect().mTop;
S32 scroll_pos = llclamp(mScrollbar->getDocPos(),
bottom, // min vertical scroll
top); // max vertical scroll
mScrollbar->setDocPos(scroll_pos);
}
return 1;
}
else if (info.has("child_visibility_change"))
{
bool new_visibility = info["child_visibility_change"];
if (new_visibility)
{
// there is at least one visible tab
mNoVisibleTabsHelpText->setVisible(false);
}
else
{
// it could be the latest visible tab, check all of them
updateNoTabsHelpTextVisibility();
}
}
return LLPanel::notifyParent(info);
}
void LLAccordionCtrl::reset()
{
if (mScrollbar)
mScrollbar->setDocPos(0);
}
void LLAccordionCtrl::expandDefaultTab()
{
if (!mAccordionTabs.empty())
{
LLAccordionCtrlTab* tab = mAccordionTabs.front();
if (!tab->getDisplayChildren())
{
tab->setDisplayChildren(true);
}
for (size_t i = 1; i < mAccordionTabs.size(); ++i)
{
tab = mAccordionTabs[i];
if (tab->getDisplayChildren())
{
tab->setDisplayChildren(false);
}
}
arrange();
}
}
void LLAccordionCtrl::sort()
{
if (!mTabComparator)
{
LL_WARNS() << "No comparator specified for sorting accordion tabs." << LL_ENDL;
return;
}
std::sort(mAccordionTabs.begin(), mAccordionTabs.end(), LLComparatorAdaptor(*mTabComparator));
arrange();
}
void LLAccordionCtrl::setFilterSubString(const std::string& filter_string)
{
LLStringUtil::format_map_t args;
args["[SEARCH_TERM]"] = LLURI::escape(filter_string);
std::string text = filter_string.empty() ? mNoVisibleTabsOrigString : mNoMatchedTabsOrigString;
LLStringUtil::format(text, args);
mNoVisibleTabsHelpText->setValue(text);
}
const LLAccordionCtrlTab* LLAccordionCtrl::getExpandedTab() const
{
const LLAccordionCtrlTab* result = nullptr;
for (LLAccordionCtrlTab* accordion_tab : mAccordionTabs)
{
if (accordion_tab->isExpanded())
{
result = accordion_tab;
break;
}
}
return result;
}
S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 available_height /* = 0 */)
{
if (tab_index < 0)
{
return available_height;
}
S32 collapsed_tabs_height = 0;
S32 num_expanded = 0;
for (LLAccordionCtrlTab* tab : mAccordionTabs)
{
if (!tab->isExpanded())
{
collapsed_tabs_height += tab->getHeaderHeight();
}
else
{
++num_expanded;
}
}
if (0 == num_expanded)
{
return available_height;
}
S32 expanded_tab_height = available_height - collapsed_tabs_height - BORDER_MARGIN; // top BORDER_MARGIN is added in arrange(), here we add bottom BORDER_MARGIN
expanded_tab_height /= num_expanded;
return expanded_tab_height;
}
void LLAccordionCtrl::collapseAllTabs()
{
if (mAccordionTabs.size() > 0)
{
for (LLAccordionCtrlTab* tab : mAccordionTabs)
{
if (tab->getDisplayChildren())
{
tab->setDisplayChildren(false);
}
}
arrange();
}
}
+204
View File
@@ -0,0 +1,204 @@
/**
* @file LLAccordionCtrl.h
* @brief Accordion Panel implementation
*
* $LicenseInfo:firstyear=2004&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_ACCORDIONCTRL_H
#define LL_ACCORDIONCTRL_H
#include "llpanel.h"
#include "lltextbox.h"
#include "llscrollbar.h"
#include <vector>
#include <algorithm>
#include <string>
class LLAccordionCtrlTab;
class LLAccordionCtrl: public LLPanel
{
private:
std::vector<LLAccordionCtrlTab*> mAccordionTabs;
void ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height);
void ctrlShiftVertical(LLView* panel,S32 delta);
void onCollapseCtrlCloseOpen(S16 panel_num);
void shiftAccordionTabs(S16 panel_num, S32 delta);
public:
/**
* Abstract comparator for accordion tabs.
*/
class LLTabComparator
{
public:
LLTabComparator() = default;
virtual ~LLTabComparator() = default;
/** Returns true if tab1 < tab2, false otherwise */
virtual bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const = 0;
};
struct Params
: public LLInitParam::Block<Params, LLPanel::Params>
{
Optional<bool> single_expansion,
fit_parent; /* Accordion will fit its parent size, controls that are placed into
accordion tabs are responsible for scrolling their content.
*NOTE fit_parent works best when combined with single_expansion.
Accordion view should implement getRequiredRect() and provide valid height*/
Optional<LLTextBox::Params> no_matched_tabs_text;
Optional<LLTextBox::Params> no_visible_tabs_text;
Params()
: single_expansion("single_expansion",false)
, fit_parent("fit_parent", false)
, no_matched_tabs_text("no_matched_tabs_text")
, no_visible_tabs_text("no_visible_tabs_text")
{};
};
LLAccordionCtrl(const Params& params);
LLAccordionCtrl();
virtual ~LLAccordionCtrl();
virtual bool postBuild();
virtual bool handleRightMouseDown ( S32 x, S32 y, MASK mask);
virtual bool handleScrollWheel ( S32 x, S32 y, S32 clicks );
virtual bool handleKeyHere (KEY key, MASK mask);
virtual bool handleDragAndDrop (S32 x, S32 y, MASK mask, bool drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
//
// Call reshape after changing splitter's size
virtual void reshape(S32 width, S32 height, bool called_from_parent = true);
// <FS:ND> If adding a lot of controls rapidly, calling arrange will cost a lot of times, as it's running through n! controls.
// In that case we can avvoid calling arrange over and over and just call it once when finished.
// void addCollapsibleCtrl(LLAccordionCtrlTab* accordion_tab);
void addCollapsibleCtrl(LLAccordionCtrlTab* accordion_tab, bool aArrange = true /*Standard is true as to not mess with old code all over the place*/ );
// </FS:ND>
void removeCollapsibleCtrl(LLAccordionCtrlTab* accordion_tab);
void arrange();
void draw();
void onScrollPosChangeCallback(S32, LLScrollbar*);
virtual void onUpdateScrollToChild(const LLUICtrl * cntrl);
void onOpen (const LLSD& key);
S32 notifyParent(const LLSD& info);
void reset ();
void expandDefaultTab();
void setComparator(const LLTabComparator* comp) { mTabComparator = comp; }
void sort();
void collapseAllTabs();
/**
* Sets filter substring as a search_term for help text when there are no any visible tabs.
*/
void setFilterSubString(const std::string& filter_string);
/**
* This method returns the first expanded accordion tab.
* It is expected to be called for accordion which doesn't allow multiple
* tabs to be expanded. Use with care.
*/
const LLAccordionCtrlTab* getExpandedTab() const;
LLAccordionCtrlTab* getSelectedTab() const { return mSelectedTab; }
bool getFitParent() const {return mFitParent;}
void setSkipScrollToChild(bool skip) { mSkipScrollToChild = skip; }
private:
void initNoTabsWidget(const LLTextBox::Params& tb_params);
void updateNoTabsHelpTextVisibility();
void arrangeSingle();
void arrangeMultiple();
// Calc Splitter's height that is necessary to display all child content
S32 calcRecuiredHeight();
S32 getRecuiredHeight() const { return mInnerRect.getHeight(); }
S32 calcExpandedTabHeight(S32 tab_index = 0, S32 available_height = 0);
void updateLayout (S32 width, S32 height);
void show_hide_scrollbar (S32 width, S32 height);
void showScrollbar (S32 width, S32 height);
void hideScrollbar (S32 width, S32 height);
bool autoScroll (S32 x, S32 y);
/**
* An adaptor for LLTabComparator
*/
struct LLComparatorAdaptor
{
LLComparatorAdaptor(const LLTabComparator& comparator) : mComparator(comparator) {};
bool operator()(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2)
{
return mComparator.compare(tab1, tab2);
}
const LLTabComparator& mComparator;
};
private:
LLRect mInnerRect;
LLScrollbar* mScrollbar = nullptr;
bool mSingleExpansion = false;
bool mFitParent = false;
bool mAutoScrolling = false;
F32 mAutoScrollRate = 0.f;
LLTextBox* mNoVisibleTabsHelpText = nullptr;
bool mSkipScrollToChild = false;
std::string mNoMatchedTabsOrigString;
std::string mNoVisibleTabsOrigString;
LLAccordionCtrlTab* mSelectedTab = nullptr;
const LLTabComparator* mTabComparator = nullptr;
};
#endif // LL_LLSPLITTER_H
File diff suppressed because it is too large Load Diff
+251
View File
@@ -0,0 +1,251 @@
/**
* @file LLAccordionCtrlTab.h
* @brief Collapsible box control implementation
*
* $LicenseInfo:firstyear=2004&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_ACCORDIONCTRLTAB_H_
#define LL_ACCORDIONCTRLTAB_H_
#include <string>
#include "llrect.h"
#include "lluictrl.h"
#include "lluicolor.h"
#include "llstyle.h"
class LLUICtrlFactory;
class LLUIImage;
class LLButton;
class LLTextBox;
class LLScrollbar;
// LLAccordionCtrlTab is a container for other controls.
// It has a Header, by clicking on which hosted controls are shown or hidden.
// When hosted controls are show - LLAccordionCtrlTab is expanded.
// When hosted controls are hidden - LLAccordionCtrlTab is collapsed.
class LLAccordionCtrlTab : public LLUICtrl
{
// Interface
public:
struct Params
: public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<bool> display_children, //expanded or collapsed after initialization
collapsible;
Optional<std::string> title;
Optional<S32> header_height,
min_width,
min_height;
// Overlay images (arrows on the left)
Mandatory<LLUIImage*> header_expand_img,
header_expand_img_pressed,
header_collapse_img,
header_collapse_img_pressed;
// Background images for the accordion tabs
Mandatory<LLUIImage*> header_image,
header_image_over,
header_image_pressed,
header_image_focused;
Optional<LLUIColor> header_bg_color,
header_text_color,
dropdown_bg_color;
Optional<bool> header_visible;
Optional<bool> fit_panel;
Optional<bool> selection_enabled;
Optional<S32> padding_left,
padding_right,
padding_top,
padding_bottom;
Params();
};
typedef LLDefaultChildRegistry child_registry_t;
virtual ~LLAccordionCtrlTab();
// Registers callback for expand/collapse events.
boost::signals2::connection setDropDownStateChangedCallback(commit_callback_t cb);
// Changes expand/collapse state
virtual void setDisplayChildren(bool display);
// Returns expand/collapse state
virtual bool getDisplayChildren() const { return mDisplayChildren; };
//set LLAccordionCtrlTab panel
void setAccordionView(LLView* panel);
LLView* getAccordionView() { return mContainerPanel; };
std::string getTitle() const;
// Set text and highlight substring in LLAccordionCtrlTabHeader
void setTitle(const std::string& title, const std::string& hl = LLStringUtil::null);
// Set text font style in LLAccordionCtrlTabHeader
void setTitleFontStyle(std::string style);
// Set text color in LLAccordionCtrlTabHeader
void setTitleColor(LLUIColor color);
boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb);
boost::signals2::connection setFocusLostCallback(const focus_signal_t::slot_type& cb);
void setSelected(bool is_selected);
bool getCollapsible() { return mCollapsible; };
void setCollapsible(bool collapsible) { mCollapsible = collapsible; };
void changeOpenClose(bool is_open);
void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close; };
bool canOpenClose() const { return mCanOpenClose; };
virtual bool postBuild();
S32 notifyParent(const LLSD& info);
S32 notify(const LLSD& info);
bool notifyChildren(const LLSD& info);
void draw();
void storeOpenCloseState();
void restoreOpenCloseState();
protected:
LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&);
friend class LLUICtrlFactory;
// Overrides
public:
// Call reshape after changing size
virtual void reshape(S32 width, S32 height, bool called_from_parent = true);
/**
* Raises notifyParent event with "child_visibility_change" = new_visibility
*/
void onVisibilityChange(bool new_visibility);
virtual void onUpdateScrollToChild(const LLUICtrl * cntrl);
// Changes expand/collapse state and triggers expand/collapse callbacks
virtual bool handleMouseDown(S32 x, S32 y, MASK mask);
virtual bool handleMouseUp(S32 x, S32 y, MASK mask);
virtual bool handleKey(KEY key, MASK mask, bool called_from_parent);
virtual bool handleToolTip(S32 x, S32 y, MASK mask);
virtual bool handleScrollWheel( S32 x, S32 y, S32 clicks );
virtual bool addChild(LLView* child, S32 tab_group = 0 );
bool isExpanded() const { return mDisplayChildren; }
S32 getHeaderHeight();
// Min size functions
void setHeaderVisible(bool value);
bool getHeaderVisible() { return mHeaderVisible;}
S32 mExpandedHeight; // Height of expanded ctrl.
// Used to restore height after expand.
S32 getPaddingLeft() const { return mPaddingLeft;}
S32 getPaddingRight() const { return mPaddingRight;}
S32 getPaddingTop() const { return mPaddingTop;}
S32 getPaddingBottom() const { return mPaddingBottom;}
void showAndFocusHeader();
void setFitPanel( bool fit ) { mFitPanel = true; }
bool getFitParent() const { return mFitPanel; }
void setIgnoreResizeNotification(bool ignore) { mSkipChangesOnNotifyParent = ignore;}
protected:
void adjustContainerPanel (const LLRect& child_rect);
void adjustContainerPanel ();
S32 getChildViewHeight ();
void onScrollPosChangeCallback(S32, LLScrollbar*);
void show_hide_scrollbar (const LLRect& child_rect);
void showScrollbar (const LLRect& child_rect);
void hideScrollbar (const LLRect& child_rect);
void updateLayout ( const LLRect& child_rect );
void ctrlSetLeftTopAndSize (LLView* panel, S32 left, S32 top, S32 width, S32 height);
void drawChild(const LLRect& root_rect,LLView* child);
LLView* findContainerView ();
void selectOnFocusReceived();
void deselectOnFocusLost();
private:
class LLAccordionCtrlTabHeader;
LLAccordionCtrlTabHeader* mHeader; //Header
bool mDisplayChildren; //Expanded/collapsed
bool mCollapsible;
bool mHeaderVisible;
bool mCanOpenClose;
bool mFitPanel;
S32 mPaddingLeft;
S32 mPaddingRight;
S32 mPaddingTop;
S32 mPaddingBottom;
bool mStoredOpenCloseState;
bool mWasStateStored;
bool mSkipChangesOnNotifyParent;
bool mSelectionEnabled;
LLScrollbar* mScrollbar;
LLView* mContainerPanel;
LLUIColor mDropdownBGColor;
};
#endif
+389
View File
@@ -0,0 +1,389 @@
/**
* @file llbadge.cpp
* @brief Implementation for badges
*
* $LicenseInfo:firstyear=2001&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$
*/
#define LLBADGE_CPP
#include "llbadge.h"
#include "llfontgl.h"
#include "llfontvertexbuffer.h"
#include "llscrollcontainer.h"
#include "lluictrlfactory.h"
static LLDefaultChildRegistry::Register<LLBadge> r("badge");
static const S32 BADGE_OFFSET_NOT_SPECIFIED = 0x7FFFFFFF;
// Compiler optimization, generate extern template
template class LLBadge* LLView::getChild<class LLBadge>(std::string_view name, bool recurse) const;
LLBadge::Params::Params()
: image("image")
, border_image("border_image")
, border_color("border_color")
, image_color("image_color")
, label("label")
, label_color("label_color")
, label_offset_horiz("label_offset_horiz")
, label_offset_vert("label_offset_vert")
, location("location", LLRelPos::TOP_LEFT)
, location_offset_hcenter("location_offset_hcenter")
, location_offset_vcenter("location_offset_vcenter")
, location_percent_hcenter("location_percent_hcenter")
, location_percent_vcenter("location_percent_vcenter")
, padding_horiz("padding_horiz")
, padding_vert("padding_vert")
{}
bool LLBadge::Params::equals(const Params& a) const
{
bool comp = true;
// skip owner in comparison on purpose
comp &= (border_image() == a.border_image());
comp &= (border_color() == a.border_color());
comp &= (image() == a.image());
comp &= (image_color() == a.image_color());
comp &= (label() == a.label());
comp &= (label_color() == a.label_color());
comp &= (label_offset_horiz() == a.label_offset_horiz());
comp &= (label_offset_vert() == a.label_offset_vert());
comp &= (location() == a.location());
comp &= (location_offset_hcenter() == a.location_offset_hcenter());
comp &= (location_offset_vcenter() == a.location_offset_vcenter());
comp &= (location_percent_hcenter() == a.location_percent_hcenter());
comp &= (location_percent_vcenter() == a.location_percent_vcenter());
comp &= (padding_horiz() == a.padding_horiz());
comp &= (padding_vert() == a.padding_vert());
return comp;
}
LLBadge::LLBadge(const LLBadge::Params& p)
: LLUICtrl(p)
, mOwner(p.owner)
, mBorderImage(p.border_image)
, mBorderColor(p.border_color)
, mGLFont(p.font)
, mImage(p.image)
, mImageColor(p.image_color)
, mLabel(p.label)
, mLabelColor(p.label_color)
, mLabelOffsetHoriz(p.label_offset_horiz)
, mLabelOffsetVert(p.label_offset_vert)
, mLocation(p.location)
, mLocationOffsetHCenter(BADGE_OFFSET_NOT_SPECIFIED)
, mLocationOffsetVCenter(BADGE_OFFSET_NOT_SPECIFIED)
, mLocationPercentHCenter(0.5f)
, mLocationPercentVCenter(0.5f)
, mPaddingHoriz(p.padding_horiz)
, mPaddingVert(p.padding_vert)
, mParentScroller(NULL)
, mDrawAtParentTop(false)
{
if (mImage.isNull())
{
LL_WARNS() << "Badge: " << getName() << " with no image!" << LL_ENDL;
}
if (p.location_offset_hcenter.isProvided())
{
mLocationOffsetHCenter = p.location_offset_hcenter();
}
if (p.location_offset_vcenter.isProvided())
{
mLocationOffsetVCenter = p.location_offset_vcenter();
}
//
// The following logic is to set the mLocationPercentHCenter and mLocationPercentVCenter
// based on the Location enum and our horizontal and vertical location percentages. The
// draw code then uses this on the owner rectangle to compute the screen location for
// the badge.
//
if (!LLRelPos::IsCenter(mLocation))
{
F32 h_center = p.location_percent_hcenter * 0.01f;
F32 v_center = p.location_percent_vcenter * 0.01f;
if (LLRelPos::IsRight(mLocation))
{
mLocationPercentHCenter = 0.5f * (1.0f + h_center);
}
else if (LLRelPos::IsLeft(mLocation))
{
mLocationPercentHCenter = 0.5f * (1.0f - h_center);
}
if (LLRelPos::IsTop(mLocation))
{
mLocationPercentVCenter = 0.5f * (1.0f + v_center);
}
else if (LLRelPos::IsBottom(mLocation))
{
mLocationPercentVCenter = 0.5f * (1.0f - v_center);
}
}
}
LLBadge::~LLBadge()
{
}
bool LLBadge::addToView(LLView * view)
{
bool child_added = view->addChild(this);
if (child_added)
{
setShape(view->getLocalRect());
// Find a parent scroll container, if there is one in case we need it for positioning
LLView * parent = mOwner.get();
while ((parent != NULL) && ((mParentScroller = dynamic_cast<LLScrollContainer *>(parent)) == NULL))
{
parent = parent->getParent();
}
}
return child_added;
}
void LLBadge::setLabel(const LLStringExplicit& label)
{
mLabel = label;
}
//
// This is a fallback function to render a rectangle for badges without a valid image
//
void renderBadgeBackground(F32 centerX, F32 centerY, F32 width, F32 height, const LLColor4U &color)
{
gGL.pushUIMatrix();
gGL.loadUIIdentity();
gGL.setSceneBlendType(LLRender::BT_REPLACE);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.color4ubv(color.mV);
gGL.texCoord2i(0, 0);
F32 x = LLFontGL::sCurOrigin.mX + centerX - width * 0.5f;
F32 y = LLFontGL::sCurOrigin.mY + centerY - height * 0.5f;
LLRectf screen_rect((F32)ll_round(x),
(F32)ll_round(y),
(F32)ll_round(x) + width,
(F32)ll_round(y) + height);
LLVector4a vertices[4];
vertices[0].set(screen_rect.mLeft, screen_rect.mTop, 1.0f);
vertices[1].set(screen_rect.mRight, screen_rect.mTop, 1.0f);
vertices[2].set(screen_rect.mLeft, screen_rect.mBottom, 1.0f);
vertices[3].set(screen_rect.mRight, screen_rect.mBottom, 1.0f);
gGL.begin(LLRender::TRIANGLE_STRIP);
{
gGL.vertexBatchPreTransformed(vertices, 4);
}
gGL.end();
gGL.popUIMatrix();
}
// virtual
void LLBadge::draw()
{
if (!mLabel.empty())
{
LLView* owner_view = mOwner.get();
if (owner_view && owner_view->isInVisibleChain())
{
//
// Calculate badge size based on label text
//
S32 badge_label_begin_offset = 0;
S32 badge_char_length = S32_MAX;
S32 badge_pixel_length = S32_MAX;
F32 *right_position_out = NULL;
bool do_not_use_ellipses = false;
F32 badge_width = (2.0f * mPaddingHoriz) +
mGLFont->getWidthF32(mLabel.getWString().c_str(), badge_label_begin_offset, badge_char_length);
F32 badge_height = (2.0f * mPaddingVert) + mGLFont->getLineHeight();
//
// Calculate badge position based on owner
//
LLRect owner_rect;
owner_view->localRectToOtherView(owner_view->getLocalRect(), & owner_rect, this);
S32 location_offset_horiz = mLocationOffsetHCenter;
S32 location_offset_vert = mLocationOffsetVCenter;
// If we're in a scroll container, do some math to keep us in the same place on screen if applicable
if (mParentScroller != NULL)
{
LLRect visibleRect = mParentScroller->getVisibleContentRect();
if (mLocationOffsetHCenter != BADGE_OFFSET_NOT_SPECIFIED)
{
if (LLRelPos::IsRight(mLocation))
{
location_offset_horiz += visibleRect.mRight;
}
else if (LLRelPos::IsLeft(mLocation))
{
location_offset_horiz += visibleRect.mLeft;
}
else // center
{
location_offset_horiz += (visibleRect.mLeft + visibleRect.mRight) / 2;
}
}
if (mLocationOffsetVCenter != BADGE_OFFSET_NOT_SPECIFIED)
{
if (LLRelPos::IsTop(mLocation))
{
location_offset_vert += visibleRect.mTop;
}
else if (LLRelPos::IsBottom(mLocation))
{
location_offset_vert += visibleRect.mBottom;
}
else // center
{
location_offset_vert += (visibleRect.mBottom + visibleRect.mTop) / 2;
}
}
}
F32 badge_center_x;
F32 badge_center_y;
// Compute x position
if (mLocationOffsetHCenter == BADGE_OFFSET_NOT_SPECIFIED)
{
badge_center_x = owner_rect.mLeft + owner_rect.getWidth() * mLocationPercentHCenter;
}
else
{
badge_center_x = (F32)location_offset_horiz;
}
// Compute y position
if (mLocationOffsetVCenter == BADGE_OFFSET_NOT_SPECIFIED)
{
if(mDrawAtParentTop)
{
badge_center_y = owner_rect.mTop - badge_height * 0.5f - 1;
}
else
{
badge_center_y = owner_rect.mBottom + owner_rect.getHeight() * mLocationPercentVCenter;
}
}
else
{
badge_center_y = (F32)location_offset_vert;
}
//
// Draw button image, if available.
// Otherwise draw basic rectangular button.
//
F32 alpha = getDrawContext().mAlpha;
if (!mImage.isNull())
{
F32 badge_x = badge_center_x - badge_width * 0.5f;
F32 badge_y = badge_center_y - badge_height * 0.5f;
mImage->drawSolid((S32) badge_x, (S32) badge_y, (S32) badge_width, (S32) badge_height, mImageColor % alpha);
if (!mBorderImage.isNull())
{
mBorderImage->drawSolid((S32) badge_x, (S32) badge_y, (S32) badge_width, (S32) badge_height, mBorderColor % alpha);
}
}
else
{
LL_DEBUGS() << "No image for badge " << getName() << " on owner " << owner_view->getName() << LL_ENDL;
renderBadgeBackground(badge_center_x, badge_center_y,
badge_width, badge_height,
mImageColor % alpha);
}
//
// Draw the label
//
mFontBuffer.render(mGLFont,
mLabel.getWString(),
badge_label_begin_offset,
badge_center_x + mLabelOffsetHoriz,
badge_center_y + mLabelOffsetVert,
mLabelColor % alpha,
LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position
LLFontGL::NORMAL, // normal text (not bold, italics, etc.)
LLFontGL::DROP_SHADOW_SOFT,
badge_char_length, badge_pixel_length,
right_position_out, do_not_use_ellipses);
}
}
}
namespace LLInitParam
{
void TypeValues<LLRelPos::Location>::declareValues()
{
declare("bottom", LLRelPos::BOTTOM);
declare("bottom_left", LLRelPos::BOTTOM_LEFT);
declare("bottom_right", LLRelPos::BOTTOM_RIGHT);
declare("center", LLRelPos::CENTER);
declare("left", LLRelPos::LEFT);
declare("right", LLRelPos::RIGHT);
declare("top", LLRelPos::TOP);
declare("top_left", LLRelPos::TOP_LEFT);
declare("top_right", LLRelPos::TOP_RIGHT);
}
}
// eof
+180
View File
@@ -0,0 +1,180 @@
/**
* @file llbadge.h
* @brief Header for badges
*
* $LicenseInfo:firstyear=2001&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_LLBADGE_H
#define LL_LLBADGE_H
#include <string>
#include "lluicolor.h"
#include "lluictrl.h"
#include "llstring.h"
#include "lluiimage.h"
#include "llview.h"
#include "llfontvertexbuffer.h"
//
// Declarations
//
class LLFontGL;
class LLFontVertexBuffer;
class LLScrollContainer;
class LLUICtrlFactory;
//
// Relative Position Alignment
//
namespace LLRelPos
{
enum Location
{
CENTER = 0,
LEFT = (1 << 0),
RIGHT = (1 << 1),
TOP = (1 << 2),
BOTTOM = (1 << 3),
BOTTOM_LEFT = (BOTTOM | LEFT),
BOTTOM_RIGHT = (BOTTOM | RIGHT),
TOP_LEFT = (TOP | LEFT),
TOP_RIGHT = (TOP | RIGHT),
};
inline bool IsBottom(Location relPos) { return (relPos & BOTTOM) == BOTTOM; }
inline bool IsCenter(Location relPos) { return (relPos == CENTER); }
inline bool IsLeft(Location relPos) { return (relPos & LEFT) == LEFT; }
inline bool IsRight(Location relPos) { return (relPos & RIGHT) == RIGHT; }
inline bool IsTop(Location relPos) { return (relPos & TOP) == TOP; }
}
// NOTE: This needs to occur before Optional<LLRelPos::Location> declaration for proper compilation.
namespace LLInitParam
{
template<>
struct TypeValues<LLRelPos::Location> : public TypeValuesHelper<LLRelPos::Location>
{
static void declareValues();
};
}
//
// Classes
//
class LLBadge
: public LLUICtrl
{
public:
struct Params
: public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional< LLHandle<LLView> > owner; // Mandatory in code but not in xml
Optional< LLUIImage* > border_image;
Optional< LLUIColor > border_color;
Optional< LLUIImage* > image;
Optional< LLUIColor > image_color;
Optional< std::string > label;
Optional< LLUIColor > label_color;
Optional< S32 > label_offset_horiz;
Optional< S32 > label_offset_vert;
Optional< LLRelPos::Location > location;
Optional< S32 > location_offset_hcenter;
Optional< S32 > location_offset_vcenter;
Optional< U32 > location_percent_hcenter;
Optional< U32 > location_percent_vcenter;
Optional< F32 > padding_horiz;
Optional< F32 > padding_vert;
Params();
bool equals(const Params&) const;
};
protected:
friend class LLUICtrlFactory;
LLBadge(const Params& p);
public:
~LLBadge();
bool addToView(LLView * view);
virtual void draw();
const std::string getLabel() const { return wstring_to_utf8str(mLabel); }
void setLabel( const LLStringExplicit& label);
void setDrawAtParentTop(bool draw_at_top) { mDrawAtParentTop = draw_at_top;}
private:
LLPointer< LLUIImage > mBorderImage;
LLUIColor mBorderColor;
const LLFontGL* mGLFont;
LLFontVertexBuffer mFontBuffer;
LLPointer< LLUIImage > mImage;
LLUIColor mImageColor;
LLUIString mLabel;
LLUIColor mLabelColor;
S32 mLabelOffsetHoriz;
S32 mLabelOffsetVert;
LLRelPos::Location mLocation;
S32 mLocationOffsetHCenter;
S32 mLocationOffsetVCenter;
F32 mLocationPercentHCenter;
F32 mLocationPercentVCenter;
LLHandle< LLView > mOwner;
F32 mPaddingHoriz;
F32 mPaddingVert;
LLScrollContainer* mParentScroller;
bool mDrawAtParentTop;
};
// Build time optimization, generate once in .cpp file
#ifndef LLBADGE_CPP
extern template class LLBadge* LLView::getChild<class LLBadge>(std::string_view name, bool recurse) const;
#endif
#endif // LL_LLBADGE_H
+45
View File
@@ -0,0 +1,45 @@
/**
* @file llbadgeholder.cpp
* @brief Source for badge holders
*
* $LicenseInfo:firstyear=2001&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$
*/
#include "llbadgeholder.h"
#include "llbadge.h"
#include "llview.h"
bool LLBadgeHolder::addBadge(LLBadge * badge)
{
bool badge_added = false;
LLView * this_view = dynamic_cast<LLView *>(this);
if (this_view && mAcceptsBadge)
{
badge_added = badge->addToView(this_view);
}
return badge_added;
}
+56
View File
@@ -0,0 +1,56 @@
/**
* @file llbadgeholder.h
* @brief Header for badge holders
*
* $LicenseInfo:firstyear=2001&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_LLBADGEHOLDER_H
#define LL_LLBADGEHOLDER_H
//
// Classes
//
class LLBadge;
class LLBadgeHolder
{
public:
LLBadgeHolder(bool acceptsBadge)
: mAcceptsBadge(acceptsBadge)
{
}
void setAcceptsBadge(bool acceptsBadge) { mAcceptsBadge = acceptsBadge; }
bool acceptsBadge() const { return mAcceptsBadge; }
virtual bool addBadge(LLBadge * badge);
private:
bool mAcceptsBadge;
};
#endif // LL_LLBADGEHOLDER_H
+148
View File
@@ -0,0 +1,148 @@
/**
* @file llbadgeowner.cpp
* @brief Class to manage badges attached to a UI control
*
* $LicenseInfo:firstyear=2001&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$
*/
#include "linden_common.h"
#include "llbadgeholder.h"
#include "llbadgeowner.h"
#include "llpanel.h"
//
// Classes
//
LLBadgeOwner::LLBadgeOwner(LLHandle< LLView > viewHandle)
: mHasBadgeHolderParent(false),
mBadge(NULL),
mBadgeOwnerView(viewHandle)
{
}
void LLBadgeOwner::initBadgeParams(const LLBadge::Params& p)
{
if (!p.equals(LLUICtrlFactory::getDefaultParams<LLBadge>()))
{
mBadge = createBadge(p);
mHasBadgeHolderParent = false;
LLView * owner_view = mBadgeOwnerView.get();
if (owner_view)
{
mBadge->addToView(owner_view);
}
}
}
void LLBadgeOwner::reshapeBadge(const LLRect& new_rect)
{
if (mBadge)
{
mBadge->setShape(new_rect);
}
}
// <FS:Ansariel> Re-add setBadgeLabel
void LLBadgeOwner::setBadgeLabel(const LLStringExplicit& label)
{
if (mBadge == NULL)
{
mBadge = createBadge(LLUICtrlFactory::getDefaultParams<LLBadge>());
addBadgeToParentHolder();
}
if (mBadge)
{
mBadge->setLabel(label);
//
// Push the badge to the front so it renders on top
//
LLView * parent = mBadge->getParent();
if (parent)
{
parent->sendChildToFront(mBadge);
}
}
}
// </FS:Ansariel>
void LLBadgeOwner::setBadgeVisibility(bool visible)
{
if (mBadge)
{
mBadge->setVisible(visible);
}
}
void LLBadgeOwner::setDrawBadgeAtTop(bool draw_at_top)
{
if (mBadge)
{
mBadge->setDrawAtParentTop(draw_at_top);
}
}
void LLBadgeOwner::addBadgeToParentHolder()
{
LLView * owner_view = mBadgeOwnerView.get();
if (mBadge && owner_view)
{
LLBadgeHolder * badge_holder = NULL;
// Find the appropriate holder for the badge
LLView * parent = owner_view->getParent();
while (parent)
{
LLBadgeHolder * badge_holder_panel = dynamic_cast<LLBadgeHolder *>(parent);
if (badge_holder_panel && badge_holder_panel->acceptsBadge())
{
badge_holder = badge_holder_panel;
break;
}
parent = parent->getParent();
}
if (badge_holder)
{
mHasBadgeHolderParent = badge_holder->addBadge(mBadge);
}
}
}
LLBadge* LLBadgeOwner::createBadge(const LLBadge::Params& p)
{
LLBadge::Params badge_params(p);
badge_params.owner = mBadgeOwnerView;
return LLUICtrlFactory::create<LLBadge>(badge_params);
}
+64
View File
@@ -0,0 +1,64 @@
/**
* @file llbadgeowner.h
* @brief Header for badge owners
*
* $LicenseInfo:firstyear=2001&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_LLBADGEOWNER_H
#define LL_LLBADGEOWNER_H
#include "llbadge.h"
#include "llview.h"
//
// Classes
//
class LLBadgeOwner
{
public:
LLBadgeOwner(LLHandle< LLView > viewHandle);
void initBadgeParams(const LLBadge::Params& p);
void addBadgeToParentHolder();
bool hasBadgeHolderParent() const { return mHasBadgeHolderParent; };
// <FS:Ansariel> Re-add setBadgeLabel
void setBadgeLabel(const LLStringExplicit& label);
// </FS:Ansariel>
void setBadgeVisibility(bool visible);
void setDrawBadgeAtTop(bool draw_at_top);
void reshapeBadge(const LLRect& new_rect);
private:
LLBadge* createBadge(const LLBadge::Params& p);
private:
bool mHasBadgeHolderParent;
LLBadge* mBadge;
LLHandle< LLView > mBadgeOwnerView;
};
#endif // LL_LLBADGEOWNER_H
File diff suppressed because it is too large Load Diff
+431
View File
@@ -0,0 +1,431 @@
/**
* @file llbutton.h
* @brief Header for buttons
*
* $LicenseInfo:firstyear=2001&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_LLBUTTON_H
#define LL_LLBUTTON_H
#include "lluuid.h"
#include "llbadgeowner.h"
#include "llcontrol.h"
#include "llflashtimer.h"
#include "lluictrl.h"
#include "v4color.h"
#include "llframetimer.h"
#include "lluiimage.h"
#include "lluistring.h"
//
// Constants
//
// PLEASE please use these "constants" when building your own buttons.
extern S32 LLBUTTON_H_PAD;
extern S32 BTN_HEIGHT_SMALL;
extern S32 BTN_HEIGHT;
extern S32 BTN_DROP_SHADOW;
//
// Helpful functions
//
S32 round_up(S32 grid, S32 value);
class LLUICtrlFactory;
class LLFontGL;
class LLFontVertexBuffer;
//
// Classes
//
class LLButton
: public LLUICtrl, public LLBadgeOwner
, public ll::ui::SearchableControl
{
public:
struct Params
: public LLInitParam::Block<Params, LLUICtrl::Params>
{
// text label
Optional<std::string> label_selected;
Optional<bool> label_shadow;
Optional<bool> auto_resize;
Optional<bool> use_ellipses;
Optional<bool> use_font_color;
// images
Optional<LLUIImage*> image_unselected,
image_selected,
image_hover_selected,
image_hover_unselected,
image_disabled_selected,
image_disabled,
image_flash,
image_pressed,
image_pressed_selected,
image_overlay;
Optional<std::string> image_overlay_alignment;
// colors
Optional<LLUIColor> label_color,
label_color_selected,
label_color_disabled,
label_color_disabled_selected,
image_color,
image_color_disabled,
image_overlay_color,
image_overlay_selected_color,
image_overlay_disabled_color,
flash_color;
// layout
Optional<S32> pad_right;
Optional<S32> pad_left;
Optional<S32> pad_bottom; // under text label
//image overlay paddings
Optional<S32> image_top_pad;
Optional<S32> image_bottom_pad;
/**
* Space between image_overlay and label
*/
Optional<S32> imgoverlay_label_space;
// callbacks
Optional<CommitCallbackParam> click_callback, // alias -> commit_callback
mouse_down_callback,
mouse_up_callback,
mouse_held_callback;
// misc
Optional<bool> is_toggle,
scale_image,
commit_on_return,
commit_on_capture_lost,
display_pressed_state;
Optional<F32> hover_glow_amount;
Optional<TimeIntervalParam> held_down_delay;
Optional<bool> use_draw_context_alpha;
Optional<LLBadge::Params> badge;
Optional<bool> handle_right_mouse;
Optional<bool> button_flash_enable;
Optional<S32> button_flash_count;
Optional<F32> button_flash_rate;
Optional<std::string> checkbox_control; // <FS:Zi> Add checkbox control toggle
Optional<EnableCallbackParam> is_toggled_callback; // <FS:Ansariel> Toggle callback check
Params();
};
protected:
friend class LLUICtrlFactory;
LLButton(const Params&);
public:
~LLButton();
// For backward compatability only
typedef boost::function<void(void*)> button_callback_t;
void addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName,
const LLUUID& imageID,const std::string& xmlTagName) const;
virtual bool handleUnicodeCharHere(llwchar uni_char) override;
virtual bool handleKeyHere(KEY key, MASK mask) override;
virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override;
virtual bool handleMouseUp(S32 x, S32 y, MASK mask) override;
virtual bool handleHover(S32 x, S32 y, MASK mask) override;
virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask) override;
virtual bool handleRightMouseUp(S32 x, S32 y, MASK mask) override;
virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) override;
virtual void draw() override;
/*virtual*/ bool postBuild() override;
void onVisibilityChange(bool visible) override;
void dirtyRect() override;
virtual void onMouseLeave(S32 x, S32 y, MASK mask) override;
virtual void onMouseCaptureLost() override;
virtual void onCommit() override;
void setUnselectedLabelColor(const LLUIColor& c);
void setSelectedLabelColor(const LLUIColor& c);
void setUseEllipses(bool use_ellipses);
void setUseFontColor(bool use_font_color);
boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb);
boost::signals2::connection setMouseDownCallback(const CommitCallbackParam& cb);
boost::signals2::connection setMouseUpCallback(const CommitCallbackParam& cb);
boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb);
boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button
boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON
// Passes a 'count' parameter in the commit param payload, i.e. param["count"])
boost::signals2::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button
// <FS:Ansariel> Toggle callback check
boost::signals2::connection setIsToggledCallback(const EnableCallbackParam& cb);
boost::signals2::connection setIsToggledCallback(const enable_signal_t::slot_type& cb);
// *TODO: Deprecate (for backwards compatability only)
boost::signals2::connection setClickedCallback( button_callback_t cb, void* data );
boost::signals2::connection setMouseDownCallback( button_callback_t cb, void* data );
boost::signals2::connection setMouseUpCallback( button_callback_t cb, void* data );
boost::signals2::connection setHeldDownCallback( button_callback_t cb, void* data );
void setHeldDownDelay( F32 seconds, S32 frames = 0) { mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; }
F32 getHeldDownTime() const { return mMouseDownTimer.getElapsedTimeF32(); }
bool toggleState();
bool getToggleState() const;
void setToggleState(bool b);
void setHighlight(bool b);
void setFlashing( bool b, bool force_flashing = false );
bool getFlashing() const { return mFlashing; }
LLFlashTimer* getFlashTimer() {return mFlashingTimer;}
void setFlashColor(const LLUIColor &color) { mFlashBgColor = color; };
void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; }
LLFontGL::HAlign getHAlign() const { return mHAlign; }
void setLeftHPad( S32 pad ) { mLeftHPad = pad; }
void setRightHPad( S32 pad ) { mRightHPad = pad; }
void setImageOverlayTopPad( S32 pad ) { mImageOverlayTopPad = pad; }
S32 getImageOverlayTopPad() const { return mImageOverlayTopPad; }
void setImageOverlayBottomPad( S32 pad ) { mImageOverlayBottomPad = pad; }
S32 getImageOverlayBottomPad() const { return mImageOverlayBottomPad; }
const std::string getLabelUnselected() const { return wstring_to_utf8str(mUnselectedLabel); }
const std::string getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); }
void setImageColor(const LLUIColor& c);
/*virtual*/ void setColor(const LLUIColor& c) override;
void setImages(const std::string &image_name, const std::string &selected_name);
void setDisabledImageColor(const LLUIColor& c) { mDisabledImageColor = c; }
void setDisabledSelectedLabelColor( const LLUIColor& c ) { mDisabledSelectedLabelColor = c; }
void setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white);
void setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white);
LLPointer<LLUIImage> getImageOverlay() { return mImageOverlay; }
LLFontGL::HAlign getImageOverlayHAlign() const { return mImageOverlayAlignment; }
// <FS:Ansariel> Setter for overlay image selectedcolor
void setImageOverlaySelectedColor(const LLColor4& color) { mImageOverlaySelectedColor = color; }
void autoResize(); // resize with label of current btn state
void resize(const LLUIString& label); // resize with label input
void setLabel(const std::string& label);
void setLabel(const LLUIString& label);
void setLabel( const LLStringExplicit& label);
virtual bool setLabelArg( const std::string& key, const LLStringExplicit& text ) override;
void setLabelUnselected(const LLStringExplicit& label);
void setLabelSelected(const LLStringExplicit& label);
void setDisabledLabelColor(const LLUIColor& c);
void setFont(const LLFontGL* font);
const LLFontGL* getFont() const override { return mGLFont; }
const std::string& getText() const override { return getCurrentLabel().getString(); }
S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; }
bool labelIsTruncated() const;
const LLUIString& getCurrentLabel() const;
void setScaleImage(bool scale) { mScaleImage = scale; }
bool getScaleImage() const { return mScaleImage; }
void setDropShadowedText(bool b);
void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; }
void setImageUnselected(LLPointer<LLUIImage> image);
void setImageSelected(LLPointer<LLUIImage> image);
void setImageHoverSelected(LLPointer<LLUIImage> image);
void setImageHoverUnselected(LLPointer<LLUIImage> image);
void setImageDisabled(LLPointer<LLUIImage> image);
void setImageDisabledSelected(LLPointer<LLUIImage> image);
void setImageFlash(LLPointer<LLUIImage> image);
void setImagePressed(LLPointer<LLUIImage> image);
void setCommitOnReturn(bool commit) { mCommitOnReturn = commit; }
bool getCommitOnReturn() const { return mCommitOnReturn; }
static void toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname);
static void setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname);
static void setDockableFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname);
static void showHelp(LLUICtrl* ctrl, const LLSD& sdname);
void setForcePressedState(bool b) { mForcePressedState = b; }
void setAutoResize(bool auto_resize) { mAutoResize = auto_resize; }
// <COLOSI opensim multi-currency support>
// Set all LLUIStrings to dirty after currency symbol change to force them to be updated.
void updateCurrencySymbols() { mUnselectedLabel.updateCurrencySymbols(); mSelectedLabel.updateCurrencySymbols(); mDisabledSelectedLabel.updateCurrencySymbols(); }
// </COLOSI opensim multi-currency support>
protected:
LLPointer<LLUIImage> getImageUnselected() const { return mImageUnselected; }
LLPointer<LLUIImage> getImageSelected() const { return mImageSelected; }
void getOverlayImageSize(S32& overlay_width, S32& overlay_height);
LLFrameTimer mMouseDownTimer;
bool mNeedsHighlight;
S32 mButtonFlashCount;
F32 mButtonFlashRate;
void drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size);
void resetMouseDownTimer();
commit_signal_t* mMouseDownSignal;
commit_signal_t* mMouseUpSignal;
commit_signal_t* mHeldDownSignal;
enable_signal_t* mIsToggledSignal; // <FS:Ansariel> Toggle callback check
S32 mMouseDownFrame;
S32 mMouseHeldDownCount; // Counter for parameter passed to held-down callback
F32 mHeldDownDelay; // seconds, after which held-down callbacks get called
S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called
S32 mLastDrawCharsCount;
LLPointer<LLUIImage> mImageOverlay;
LLFontGL::HAlign mImageOverlayAlignment;
LLUIColor mImageOverlayColor;
LLUIColor mImageOverlaySelectedColor;
LLUIColor mImageOverlayDisabledColor;
LLPointer<LLUIImage> mImageUnselected;
LLUIString mUnselectedLabel;
LLUIColor mUnselectedLabelColor;
LLPointer<LLUIImage> mImageSelected;
LLUIString mSelectedLabel;
LLUIColor mSelectedLabelColor;
LLPointer<LLUIImage> mImageHoverSelected;
LLPointer<LLUIImage> mImageHoverUnselected;
LLPointer<LLUIImage> mImageDisabled;
LLUIColor mDisabledLabelColor;
LLPointer<LLUIImage> mImageDisabledSelected;
LLUIString mDisabledSelectedLabel;
LLUIColor mDisabledSelectedLabelColor;
LLPointer<LLUIImage> mImagePressed;
LLPointer<LLUIImage> mImagePressedSelected;
/* There are two ways an image can flash- by making changes in color according to flash_color attribute
or by changing icon from current to the one specified in image_flash. Second way is used only if
flash icon name is set in attributes(by default it isn't). First way is used otherwise. */
LLPointer<LLUIImage> mImageFlash;
LLUIColor mFlashBgColor;
LLUIColor mImageColor;
LLUIColor mDisabledImageColor;
bool mIsToggle;
bool mScaleImage;
bool mDropShadowedText;
bool mAutoResize;
bool mUseEllipses;
bool mUseFontColor;
bool mFlashing;
LLFontGL::HAlign mHAlign;
S32 mLeftHPad;
S32 mRightHPad;
S32 mBottomVPad; // under text label
S32 mImageOverlayTopPad;
S32 mImageOverlayBottomPad;
bool mUseDrawContextAlpha;
/*
* Space between image_overlay and label
*/
S32 mImgOverlayLabelSpace;
F32 mHoverGlowStrength;
F32 mCurGlowStrength;
bool mCommitOnReturn;
bool mCommitOnCaptureLost;
bool mFadeWhenDisabled;
bool mForcePressedState;
bool mDisplayPressedState;
LLFrameTimer mFrameTimer;
LLFlashTimer * mFlashingTimer;
bool mForceFlashing; // Stick flashing color even if button is pressed
bool mHandleRightMouse;
// <FS:Zi> Add checkbox control toggle
std::string mCheckboxControl;
LLPanel* mCheckboxControlPanel;
// </FS:Zi>
private:
const LLFontGL* mGLFont;
LLFontVertexBuffer mFontBuffer;
protected:
virtual std::string _getSearchText() const override
{
// <FS:PP> Look in name attributes, making search independent from localization
// return getLabelUnselected() + getToolTip();
return getLabelUnselected() + getToolTip() + getName();
// </FS:PP>
}
};
// Build time optimization, generate once in .cpp file
#ifndef LLBUTTON_CPP
extern template class LLButton* LLView::getChild<class LLButton>(
std::string_view name, bool recurse) const;
#endif
#endif // LL_LLBUTTON_H
+58
View File
@@ -0,0 +1,58 @@
/**
* @file llcallbackmap.h
* @brief LLCallbackMap base class
*
* $LicenseInfo:firstyear=2006&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 LLCALLBACKMAP_H
#define LLCALLBACKMAP_H
#include <map>
#include <string>
#include <boost/function.hpp>
class LLCallbackMap
{
public:
// callback definition.
typedef boost::function<void* (void* data)> callback_t;
typedef std::map<std::string, LLCallbackMap> map_t;
typedef map_t::iterator map_iter_t;
typedef map_t::const_iterator map_const_iter_t;
template <class T>
static void* buildPanel(void* data)
{
T* panel = new T();
return (void*)panel;
}
LLCallbackMap() : mCallback(NULL), mData(NULL) { }
LLCallbackMap(callback_t callback, void* data = NULL) : mCallback(callback), mData(data) { }
callback_t mCallback;
void* mData;
};
#endif // LLCALLBACKMAP_H
+130
View File
@@ -0,0 +1,130 @@
/**
* @file llchat.h
* @author James Cook
* @brief Chat constants and data structures.
*
* $LicenseInfo:firstyear=2006&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_LLCHAT_H
#define LL_LLCHAT_H
#include "lluuid.h"
#include "v3math.h"
// enumerations used by the chat system
typedef enum e_chat_source_type
{
CHAT_SOURCE_SYSTEM = 0,
CHAT_SOURCE_AGENT = 1,
CHAT_SOURCE_OBJECT = 2,
CHAT_SOURCE_TELEPORT = 3,
CHAT_SOURCE_UNKNOWN = 4,
CHAT_SOURCE_REGION = 5,
} EChatSourceType;
typedef enum e_chat_type
{
CHAT_TYPE_WHISPER = 0,
CHAT_TYPE_NORMAL = 1,
CHAT_TYPE_SHOUT = 2,
CHAT_TYPE_OOC = 3,
CHAT_TYPE_START = 4,
CHAT_TYPE_STOP = 5,
CHAT_TYPE_DEBUG_MSG = 6,
CHAT_TYPE_REGION = 7,
CHAT_TYPE_OWNER = 8,
CHAT_TYPE_DIRECT = 9, // From llRegionSayTo()
CHAT_TYPE_IM = 10, // Ansariel: Special type for IMs in nearby chat
CHAT_TYPE_IM_GROUP = 11, // FS:LO FIRE-5230 - Chat Console Improvement: Replacing the "IM" in front of group chat messages with the actual group name
CHAT_TYPE_RADAR = 12 // FS:LO FIRE-1439 - Clickable avatar names on local chat radar crossing reports
} EChatType;
typedef enum e_chat_audible_level
{
CHAT_AUDIBLE_NOT = -1,
CHAT_AUDIBLE_BARELY = 0,
CHAT_AUDIBLE_FULLY = 1
} EChatAudible;
typedef enum e_chat_style
{
CHAT_STYLE_NORMAL,
CHAT_STYLE_IRC,
CHAT_STYLE_HISTORY,
CHAT_STYLE_TELEPORT_SEP,
// <FS:Zi> Add a distinct color for server side group chat replay
// CHAT_STYLE_MODERATOR
CHAT_STYLE_MODERATOR,
CHAT_STYLE_SERVER_HISTORY
// </FS:Zi>
}EChatStyle;
// A piece of chat
class LLChat
{
public:
LLChat(const std::string& text = std::string())
: mText(text),
mFromName(),
mFromID(),
mNotifId(),
mOwnerID(),
mSourceType(CHAT_SOURCE_AGENT),
mChatType(CHAT_TYPE_NORMAL),
mAudible(CHAT_AUDIBLE_FULLY),
mMuted(false),
// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a
mRlvLocFiltered(false),
mRlvNamesFiltered(false),
// [/RLVa:KB]
mTime(0.0),
mTimeStr(),
mPosAgent(),
mURL(),
mChatStyle(CHAT_STYLE_NORMAL),
mSessionID()
{ }
std::string mText; // UTF-8 line of text
std::string mFromName; // agent or object name
std::string mFromNameGroup; // FS:LO FIRE-5230 - Chat Console Improvement: Replacing the "IM" in front of group chat messages with the actual group name
LLUUID mFromID; // agent id or object id
LLUUID mNotifId;
LLUUID mOwnerID;
EChatSourceType mSourceType;
EChatType mChatType;
EChatAudible mAudible;
bool mMuted; // pass muted chat to maintain list of chatters
// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a
bool mRlvLocFiltered;
bool mRlvNamesFiltered;
// [/RLVa:KB]
F64 mTime; // viewer only, seconds from viewer start
std::string mTimeStr;
LLVector3 mPosAgent;
std::string mURL;
EChatStyle mChatStyle;
LLUUID mSessionID;
};
#endif
+288
View File
@@ -0,0 +1,288 @@
/**
* @file llchatentry.cpp
* @brief LLChatEntry implementation
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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$
*/
#include "linden_common.h"
#include "llscrollcontainer.h"
#include "llchatentry.h"
static LLDefaultChildRegistry::Register<LLChatEntry> r("chat_editor");
LLChatEntry::Params::Params()
: has_history("has_history", true),
is_expandable("is_expandable", false),
expand_lines_count("expand_lines_count", 1)
{}
LLChatEntry::LLChatEntry(const Params& p)
: LLTextEditor(p),
mTextExpandedSignal(NULL),
mHasHistory(p.has_history),
mIsExpandable(p.is_expandable),
mExpandLinesCount(p.expand_lines_count),
mPrevLinesCount(0),
mSingleLineMode(false),
mPrevExpandedLineCount(S32_MAX),
// <FS:Ansariel> FIRE-12537: CTRL-UP discards current input
mCurrentInput("")
{
// Initialize current history line iterator
mCurrentHistoryLine = mLineHistory.begin();
mAutoIndent = false;
keepSelectionOnReturn(true);
}
LLChatEntry::~LLChatEntry()
{
delete mTextExpandedSignal;
}
void LLChatEntry::draw()
{
if(mIsExpandable)
{
reflow();
expandText();
}
LLTextEditor::draw();
}
void LLChatEntry::onCommit()
{
updateHistory();
LLTextEditor::onCommit();
}
boost::signals2::connection LLChatEntry::setTextExpandedCallback(const commit_signal_t::slot_type& cb)
{
if (!mTextExpandedSignal)
{
mTextExpandedSignal = new commit_signal_t();
}
return mTextExpandedSignal->connect(cb);
}
void LLChatEntry::expandText()
{
S32 line_count = mSingleLineMode ? 1 : mExpandLinesCount;
// <FS:Ansariel> Store result of getVisibleLines - it calls reflow
//int visible_lines_count = llabs(getVisibleLines(true).first - getVisibleLines(true).second);
std::pair<S32, S32> visible_lines = getVisibleLines(true);
int visible_lines_count = llabs(visible_lines.first - visible_lines.second);
// </FS:Ansariel>
bool can_changed = getLineCount() <= line_count || line_count < mPrevExpandedLineCount ;
mPrevExpandedLineCount = line_count;
// true if pasted text has more lines than expand height limit and expand limit is not reached yet
bool text_pasted = (getLineCount() > line_count) && (visible_lines_count < line_count);
if (mIsExpandable && (can_changed || text_pasted || mSingleLineMode) && getLineCount() != mPrevLinesCount)
{
int lines_height = 0;
if (text_pasted)
{
// text is pasted and now mLineInfoList.size() > mExpandLineCounts and mLineInfoList is not empty,
// so lines_height is the sum of the last 'expanded_line_count' lines height
lines_height = (mLineInfoList.end() - line_count)->mRect.mTop - mLineInfoList.back().mRect.mBottom;
}
else
{
lines_height = mLineInfoList.begin()->mRect.mTop - mLineInfoList.back().mRect.mBottom;
}
int height = mVPad * 2 + lines_height;
LLRect doc_rect = getRect();
doc_rect.setOriginAndSize(doc_rect.mLeft, doc_rect.mBottom, doc_rect.getWidth(), height);
setShape(doc_rect);
mPrevLinesCount = getLineCount();
if (mTextExpandedSignal)
{
(*mTextExpandedSignal)(this, LLSD() );
}
needsReflow();
}
}
// line history support
void LLChatEntry::updateHistory()
{
// On history enabled, remember committed line and
// reset current history line number.
// Be sure only to remember lines that are not empty and that are
// different from the last on the list.
if (mHasHistory && getLength())
{
// Add text to history, ignoring duplicates
if (mLineHistory.empty() || getText() != mLineHistory.back())
{
mLineHistory.push_back(getText());
}
mCurrentHistoryLine = mLineHistory.end();
}
}
void LLChatEntry::beforeValueChange()
{
if(this->getLength() == 0 && !mLabel.empty())
{
this->clearSegments();
}
}
void LLChatEntry::onValueChange(S32 start, S32 end)
{
//Internally resetLabel() must meet a condition before it can reset the label
resetLabel();
}
bool LLChatEntry::useLabel() const
{
return !getLength() && !mLabel.empty();
}
void LLChatEntry::onFocusReceived()
{
LLUICtrl::onFocusReceived();
updateAllowingLanguageInput();
}
void LLChatEntry::onFocusLost()
{
LLTextEditor::focusLostHelper();
LLUICtrl::onFocusLost();
}
bool LLChatEntry::handleSpecialKey(const KEY key, const MASK mask)
{
bool handled = false;
LLTextEditor::handleSpecialKey(key, mask);
switch(key)
{
case KEY_RETURN:
if (MASK_NONE == mask)
{
needsReflow();
}
// <FS:Ansariel> FIRE-12537: CTRL-UP discards current input
mCurrentInput = "";
break;
case KEY_UP:
if (mHasHistory && MASK_CONTROL == mask)
{
if (!mLineHistory.empty() && mCurrentHistoryLine > mLineHistory.begin())
{
// <FS:Ansariel> FIRE-12537: CTRL-UP discards current input
if (mCurrentHistoryLine == mLineHistory.end())
{
mCurrentInput = getText();
}
// </FS:Ansariel>
setText(*(--mCurrentHistoryLine));
endOfDoc();
}
else
{
LLUI::getInstance()->reportBadKeystroke();
}
handled = true;
}
break;
case KEY_DOWN:
if (mHasHistory && MASK_CONTROL == mask)
{
if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1) )
{
setText(*(++mCurrentHistoryLine));
endOfDoc();
}
else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1) )
{
mCurrentHistoryLine++;
// <FS:Ansariel> FIRE-12537: CTRL-UP discards current input
//std::string empty("");
//setText(empty);
setText(mCurrentInput);
// </FS:Ansariel>
needsReflow();
endOfDoc();
}
else
{
LLUI::getInstance()->reportBadKeystroke();
}
handled = true;
}
break;
default:
break;
}
return handled;
}
void LLChatEntry::enableSingleLineMode(bool single_line_mode)
{
if (mScroller)
{
mScroller->setSize(single_line_mode ? 0 : -1);
}
mSingleLineMode = single_line_mode;
mPrevLinesCount = -1;
setWordWrap(!single_line_mode);
}
// <FS:Ansariel> Fix linefeed pasting
//virtual
void LLChatEntry::paste()
{
LLTextEditor::paste();
if (mSingleLineMode)
{
S32 cursor_pos = getCursorPos();
LLWString content = getWText();
LLWStringUtil::replaceChar(content, '\n', llwchar(182));
setWText(content);
setCursorPos(cursor_pos);
}
}
// </FS:Ansariel>
+116
View File
@@ -0,0 +1,116 @@
/**
* @file llchatentry.h
* @author Paul Guslisty
* @brief Text editor widget which is used for user input
*
* Features:
* Optional line history so previous entries can be recalled by CTRL UP/DOWN
* Optional auto-resize behavior on input chat field
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 LLCHATENTRY_H_
#define LLCHATENTRY_H_
#include "lltexteditor.h"
class LLChatEntry : public LLTextEditor
{
public:
struct Params : public LLInitParam::Block<Params, LLTextEditor::Params>
{
Optional<bool> has_history,
is_expandable;
Optional<int> expand_lines_count;
Params();
};
virtual ~LLChatEntry();
protected:
friend class LLUICtrlFactory;
LLChatEntry(const Params& p);
/*virtual*/ void beforeValueChange();
/*virtual*/ void onValueChange(S32 start, S32 end);
/*virtual*/ bool useLabel() const;
public:
virtual void draw();
virtual void onCommit();
/*virtual*/ void onFocusReceived();
/*virtual*/ void onFocusLost();
void enableSingleLineMode(bool single_line_mode);
boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb);
// <FS:Ansariel> Changed to public so we can update history when using modifier keys
void updateHistory();
// <FS:Ansariel> Fix linefeed pasting
/*virtual*/ void paste();
private:
/**
* Implements auto-resize behavior.
* When user's typing reaches the right edge of the chat field
* the chat field expands vertically by one line. The bottom of
* the chat field remains bottom-justified. The chat field does
* not expand beyond mExpandLinesCount.
*/
void expandText();
/**
* Implements line history so previous entries can be recalled by CTRL UP/DOWN
*/
// <FS:Ansariel> Changed to public so we can update history when using modifier keys
//void updateHistory();
bool handleSpecialKey(const KEY key, const MASK mask);
// Fired when text height expanded to mExpandLinesCount
commit_signal_t* mTextExpandedSignal;
// line history support:
typedef std::vector<std::string> line_history_t;
line_history_t::iterator mCurrentHistoryLine; // currently browsed history line
line_history_t mLineHistory; // line history storage
bool mHasHistory; // flag for enabled/disabled line history
bool mIsExpandable;
bool mSingleLineMode;
S32 mExpandLinesCount;
S32 mPrevLinesCount;
S32 mPrevExpandedLineCount;
// <FS:Ansariel> FIRE-12537: CTRL-UP discards current input
std::string mCurrentInput;
};
#endif /* LLCHATENTRY_H_ */
+330
View File
@@ -0,0 +1,330 @@
/**
* @file llcheckboxctrl.cpp
* @brief LLCheckBoxCtrl base class
*
* $LicenseInfo:firstyear=2001&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$
*/
// The mutants are coming!
#include "linden_common.h"
#define LLCHECKBOXCTRL_CPP
#include "llcheckboxctrl.h"
#include "llgl.h"
#include "llui.h"
#include "lluiconstants.h"
#include "lluictrlfactory.h"
#include "llcontrol.h"
#include "llstring.h"
#include "llfontgl.h"
#include "lltextbox.h"
#include "llkeyboard.h"
static LLDefaultChildRegistry::Register<LLCheckBoxCtrl> r("check_box");
// Compiler optimization, generate extern template
template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>(
std::string_view name, bool recurse) const;
void LLCheckBoxCtrl::WordWrap::declareValues()
{
declare("none", EWordWrap::WRAP_NONE);
declare("down", EWordWrap::WRAP_DOWN);
declare("up", EWordWrap::WRAP_UP);
}
LLCheckBoxCtrl::Params::Params()
: initial_value("initial_value", false),
label_text("label_text"),
check_button("check_button"),
word_wrap("word_wrap", EWordWrap::WRAP_NONE),
// <FS:Ansariel> on_check callback parameter
on_check("on_check"),
// </FS:Ansariel>
radio_style("radio_style")
{}
LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
: LLUICtrl(p),
mTextEnabledColor(p.label_text.text_color()),
mTextDisabledColor(p.label_text.text_readonly_color()),
mFont(p.font()),
mWordWrap(p.word_wrap)
{
mViewModel->setValue(LLSD(p.initial_value));
mViewModel->resetDirty();
static LLUICachedControl<S32> llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0);
static LLUICachedControl<S32> llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0);
static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0);
// must be big enough to hold all children
setUseBoundingRect(true);
// *HACK Get rid of this with SL-55508...
// this allows blank check boxes and radio boxes for now
std::string local_label = p.label;
if(local_label.empty())
{
local_label = " ";
}
LLTextBox::Params tbparams = p.label_text;
tbparams.initial_value(local_label);
if (p.font.isProvided())
{
tbparams.font(p.font);
}
mLabel = LLUICtrlFactory::create<LLTextBox>(tbparams);
if (mWordWrap != WRAP_NONE)
{
// Not setWordWrap(mWordWrap != WRAP_NONE) because there might be some old lurking code that sets it manually
mLabel->setWordWrap(true);
S32 new_width = getRect().getWidth() - p.check_button.rect().getWidth() - llcheckboxctrl_hpad;
LLRect label_rect = mLabel->getRect();
label_rect.mRight = label_rect.mLeft + new_width;
mLabel->setRect(label_rect);
}
mLabel->reshapeToFitText();
LLRect label_rect = mLabel->getRect();
if (mLabel->getLineCount() > 1)
{
if (mWordWrap == WRAP_DOWN)
{
// reshapeToFitText uses LLView::reshape() which always reshapes
// from bottom to top, but we want to extend the bottom
// Note: might be better idea to use getRect().mTop of LLCheckBoxCtrl (+pad) as top point of new rect
S32 delta = ll_round((F32)mLabel->getFont()->getLineHeight() * mLabel->getLineSpacingMult()) - label_rect.getHeight();
label_rect.translate(0, delta);
mLabel->setRect(label_rect);
}
// else
// WRAP_UP is essentially done by reshapeToFitText() (extends from bottom to top)
// howhever it doesn't respect rect of checkbox
// todo: this should be fixed, but there are at least couple checkboxes that use this feature as is.
}
addChild(mLabel);
// Button
// Note: button cover the label by extending all the way to the right and down.
LLRect btn_rect = p.check_button.rect();
btn_rect.setOriginAndSize(
btn_rect.mLeft,
llmin(btn_rect.mBottom, label_rect.mBottom),
llmax(btn_rect.mRight, label_rect.mRight - btn_rect.mLeft),
llmax(label_rect.getHeight(), btn_rect.mTop));
std::string active_true_id, active_false_id;
std::string inactive_true_id, inactive_false_id;
LLButton::Params params = p.check_button;
params.rect(btn_rect);
//params.control_name(p.control_name);
params.click_callback.function(boost::bind(&LLCheckBoxCtrl::onCommit, this));
params.commit_on_return(false);
// Checkboxes only allow boolean initial values, but buttons can
// take any LLSD.
params.initial_value(LLSD(p.initial_value));
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
mButton = LLUICtrlFactory::create<LLButton>(params);
addChild(mButton);
// <FS:Ansariel> on_check callback parameter
if (p.on_check.isProvided())
{
setCheckCallback(initEnableCallback(p.on_check));
}
// </FS:Ansariel>
}
LLCheckBoxCtrl::~LLCheckBoxCtrl()
{
// Children all cleaned up by default view destructor.
}
void LLCheckBoxCtrl::onCommit()
{
if( getEnabled() )
{
setTentative(false);
setControlValue(getValue());
LLUICtrl::onCommit();
}
}
void LLCheckBoxCtrl::setEnabled(bool b)
{
LLView::setEnabled(b);
if (b)
{
mLabel->setColor( mTextEnabledColor );
}
else
{
mLabel->setColor( mTextDisabledColor );
}
}
void LLCheckBoxCtrl::clear()
{
setValue( false );
}
void LLCheckBoxCtrl::reshape(S32 width, S32 height, bool called_from_parent)
{
LLRect rect = getRect();
S32 delta_width = width - rect.getWidth();
S32 delta_height = height - rect.getHeight();
if (delta_width || delta_height)
{
// adjust our rectangle
rect.mRight = getRect().mLeft + width;
rect.mTop = getRect().mBottom + height;
setRect(rect);
}
// reshapeToFitText reshapes label to minimal size according to last bounding box
// it will work fine in case of decrease of space, but if we get more space or text
// becomes longer, label will fail to grow so reinit label's dimentions.
LLRect label_rect = mLabel->getRect();
S32 new_width = rect.getWidth() - label_rect.mLeft;
mLabel->reshape(new_width, label_rect.getHeight(), true);
S32 label_top = label_rect.mTop;
mLabel->reshapeToFitText(true);
label_rect = mLabel->getRect();
if (label_top != label_rect.mTop && mWordWrap == WRAP_DOWN)
{
// reshapeToFitText uses LLView::reshape() which always reshapes
// from bottom to top, but we want to extend the bottom so
// reposition control
S32 delta = label_top - label_rect.mTop;
label_rect.translate(0, delta);
mLabel->setRect(label_rect);
}
// Button
// Note: button cover the label by extending all the way to the right and down.
LLRect btn_rect = mButton->getRect();
btn_rect.setOriginAndSize(
btn_rect.mLeft,
llmin(btn_rect.mBottom, label_rect.mBottom),
llmax(btn_rect.getWidth(), label_rect.mRight - btn_rect.mLeft),
llmax(label_rect.mTop - btn_rect.mBottom, btn_rect.getHeight()));
mButton->setShape(btn_rect);
updateBoundingRect();
}
//virtual
void LLCheckBoxCtrl::setValue(const LLSD& value )
{
mButton->setValue( value );
}
//virtual
LLSD LLCheckBoxCtrl::getValue() const
{
return mButton->getValue();
}
//virtual
void LLCheckBoxCtrl::setTentative(bool b)
{
mButton->setTentative(b);
}
//virtual
bool LLCheckBoxCtrl::getTentative() const
{
return mButton->getTentative();
}
void LLCheckBoxCtrl::setLabel( const LLStringExplicit& label )
{
mLabel->setText( label );
reshape(getRect().getWidth(), getRect().getHeight(), false);
}
std::string LLCheckBoxCtrl::getLabel() const
{
return mLabel->getText();
}
bool LLCheckBoxCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text )
{
bool res = mLabel->setTextArg(key, text);
reshape(getRect().getWidth(), getRect().getHeight(), false);
return res;
}
// virtual
void LLCheckBoxCtrl::setControlName(const std::string& control_name, LLView* context)
{
mButton->setControlName(control_name, context);
}
// virtual Returns true if the user has modified this control.
bool LLCheckBoxCtrl::isDirty() const
{
if ( mButton )
{
return mButton->isDirty();
}
return false; // Shouldn't get here
}
// virtual Clear dirty state
void LLCheckBoxCtrl::resetDirty()
{
if ( mButton )
{
mButton->resetDirty();
}
}
// <FS:Ansariel> on_check callback parameter
// virtual
void LLCheckBoxCtrl::draw()
{
if (!mCheckSignal.empty())
{
bool checked = mCheckSignal(this, LLSD());
if (getValue().asBoolean() != checked)
{
setValue(checked);
}
}
LLUICtrl::draw();
}
// </FS:Ansariel>
+176
View File
@@ -0,0 +1,176 @@
/**
* @file llcheckboxctrl.h
* @brief LLCheckBoxCtrl base class
*
* $LicenseInfo:firstyear=2001&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_LLCHECKBOXCTRL_H
#define LL_LLCHECKBOXCTRL_H
#include "lluictrl.h"
#include "llbutton.h"
#include "lltextbox.h"
#include "v4color.h"
//
// Constants
//
const bool RADIO_STYLE = true;
const bool CHECK_STYLE = false;
//
// Classes
//
class LLFontGL;
class LLViewBorder;
class LLCheckBoxCtrl
: public LLUICtrl
, public ll::ui::SearchableControl
{
public:
enum EWordWrap
{
WRAP_NONE,
WRAP_UP,
WRAP_DOWN
};
struct WordWrap : public LLInitParam::TypeValuesHelper<EWordWrap, WordWrap>
{
static void declareValues();
};
struct Params
: public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<bool> initial_value; // override LLUICtrl initial_value
Optional<LLTextBox::Params> label_text;
Optional<LLButton::Params> check_button;
Optional<EWordWrap, WordWrap> word_wrap;
// <FS:Ansariel> on_check callback parameter
Optional<EnableCallbackParam> on_check;
// </FS:Ansariel>
Ignored radio_style;
Params();
};
virtual ~LLCheckBoxCtrl();
protected:
LLCheckBoxCtrl(const Params&);
friend class LLUICtrlFactory;
public:
// LLView interface
virtual void setEnabled( bool b );
virtual void reshape(S32 width, S32 height, bool called_from_parent = true);
// LLUICtrl interface
virtual void setValue(const LLSD& value );
virtual LLSD getValue() const;
bool get() { return (bool)getValue().asBoolean(); }
void set(bool value) { setValue(value); }
virtual void setTentative(bool b);
virtual bool getTentative() const;
virtual bool setLabelArg( const std::string& key, const LLStringExplicit& text );
virtual void clear();
virtual void onCommit();
// LLCheckBoxCtrl interface
virtual bool toggle() { return mButton->toggleState(); } // returns new state
void setBtnFocus() { mButton->setFocus(true); }
void setEnabledColor( const LLUIColor&color ) { mTextEnabledColor = color; }
void setDisabledColor( const LLUIColor&color ) { mTextDisabledColor = color; }
void setLabel( const LLStringExplicit& label );
std::string getLabel() const;
void setFont( const LLFontGL* font ) { mFont = font; }
const LLFontGL* getFont() const { return mFont; }
virtual void setControlName(const std::string& control_name, LLView* context);
virtual bool isDirty() const; // Returns true if the user has modified this control.
virtual void resetDirty(); // Clear dirty state
// <FS:Ansariel> on_check callback parameter
virtual void draw();
boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb )
{
return mCheckSignal.connect(cb);
}
private:
enable_signal_t mCheckSignal;
// </FS:Ansariel>
protected:
virtual std::string _getSearchText() const
{
// <FS:PP> Look in name attributes, making search independent from localization
// return getLabel() + getToolTip();
return getLabel() + getToolTip() + getName();
// </FS:PP>
}
virtual void onSetHighlight() const // When highlight, really do highlight the label
{
if( mLabel )
mLabel->ll::ui::SearchableControl::setHighlighted( ll::ui::SearchableControl::getHighlighted() );
}
protected:
// note: value is stored in toggle state of button
LLButton* mButton;
LLTextBox* mLabel;
const LLFontGL* mFont;
LLUIColor mTextEnabledColor;
LLUIColor mTextDisabledColor;
EWordWrap mWordWrap; // off, shifts text up, shifts text down
};
// Build time optimization, generate once in .cpp file
#ifndef LLCHECKBOXCTRL_CPP
extern template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>(
std::string_view name, bool recurse) const;
#endif
#endif // LL_LLCHECKBOXCTRL_H
+155
View File
@@ -0,0 +1,155 @@
/**
* @file llclipboard.cpp
* @brief LLClipboard base class
*
* $LicenseInfo:firstyear=2001&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$
*/
#include "linden_common.h"
#include "llclipboard.h"
#include "llerror.h"
#include "llmath.h"
#include "llstring.h"
#include "llview.h"
#include "llwindow.h"
LLClipboard::LLClipboard() :
mGeneration(0)
{
reset();
}
LLClipboard::~LLClipboard()
{
reset();
}
void LLClipboard::reset()
{
// Increment the clipboard count
mGeneration++;
// Clear the clipboard
mObjects.clear();
mCutMode = false;
mString = LLWString();
}
// Copy the input uuid to the LL clipboard
bool LLClipboard::copyToClipboard(const LLUUID& src, const LLAssetType::EType type)
{
reset();
return addToClipboard(src, type);
}
// Add the input uuid to the LL clipboard
// Convert the uuid to string and concatenate that string to the system clipboard if legit
bool LLClipboard::addToClipboard(const LLUUID& src, const LLAssetType::EType type)
{
bool res = false;
if (src.notNull())
{
res = true;
if (LLAssetType::lookupIsAssetIDKnowable(type))
{
LLWString source = utf8str_to_wstring(src.asString());
res = addToClipboard(source, 0, static_cast<S32>(source.size()));
}
if (res)
{
mObjects.push_back(src);
mGeneration++;
}
}
return res;
}
bool LLClipboard::pasteFromClipboard(std::vector<LLUUID>& inv_objects) const
{
bool res = false;
auto count = mObjects.size();
inv_objects.reserve(inv_objects.size() + count);
if (count > 0)
{
res = true;
inv_objects.clear();
for (size_t i = 0; i < count; i++)
{
inv_objects.push_back(mObjects[i]);
}
}
return res;
}
// Returns true if the LL Clipboard has pasteable items in it
bool LLClipboard::hasContents() const
{
return (mObjects.size() > 0);
}
// Returns true if the input uuid is in the list of clipboard objects
bool LLClipboard::isOnClipboard(const LLUUID& object) const
{
std::vector<LLUUID>::const_iterator iter = std::find(mObjects.begin(), mObjects.end(), object);
return (iter != mObjects.end());
}
// Copy the input string to the LL and the system clipboard
bool LLClipboard::copyToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary)
{
return addToClipboard(src, pos, len, use_primary);
}
// Concatenate the input string to the LL and the system clipboard
bool LLClipboard::addToClipboard(const LLWString &src, S32 pos, S32 len, bool use_primary)
{
try
{
mString = src.substr(pos, len);
}
catch (const std::exception& e)
{
LL_WARNS() << "Can't add the substring to clipboard: " << e.what() << LL_ENDL;
return false;
}
return (use_primary ? LLView::getWindow()->copyTextToPrimary(mString) : LLView::getWindow()->copyTextToClipboard(mString));
}
// Copy the System clipboard to the output string.
// Manage the LL Clipboard / System clipboard consistency
bool LLClipboard::pasteFromClipboard(LLWString &dst, bool use_primary)
{
bool res = (use_primary ? LLView::getWindow()->pasteTextFromPrimary(dst) : LLView::getWindow()->pasteTextFromClipboard(dst));
if (res)
{
mString = dst;
}
return res;
}
// Return true if there's something on the System clipboard
bool LLClipboard::isTextAvailable(bool use_primary) const
{
return (use_primary ? LLView::getWindow()->isPrimaryTextAvailable() : LLView::getWindow()->isClipboardTextAvailable());
}
+93
View File
@@ -0,0 +1,93 @@
/**
* @file llclipboard.h
* @brief LLClipboard base class
*
* $LicenseInfo:firstyear=2001&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_LLCLIPBOARD_H
#define LL_LLCLIPBOARD_H
#include <boost/function.hpp>
#include "llstring.h"
#include "lluuid.h"
#include "llsingleton.h"
#include "llassettype.h"
#include "llinventory.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLClipboard
//
// This class is used to cut/copy/paste text strings and inventory items around
// the world. Use LLClipboard::instance().method() to use its methods.
// Note that the text and UUIDs are loosely coupled only. There are few cases
// where the viewer does offer a serialized version of the UUID on the clipboard.
// In those case, the text is overridden when copying/cutting the item.
// In all other cases, the text and the UUIDs are very much independent.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLClipboard : public LLSingleton<LLClipboard>
{
LLSINGLETON(LLClipboard);
~LLClipboard();
public:
// Clears the clipboard
void reset();
// Returns the state of the clipboard so client can know if it has been modified (comparing with tracked state)
int getGeneration() const { return mGeneration; }
// Text strings management:
// ------------------------
// We support two flavors of text clipboards. The default is the explicitly
// copy-and-pasted clipboard. The second is the so-called 'primary' clipboard
// which is implicitly copied upon selection on platforms which expect this
// (i.e. X11/Linux, Mac).
bool copyToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false);
bool addToClipboard(const LLWString& src, S32 pos, S32 len, bool use_primary = false);
bool pasteFromClipboard(LLWString& dst, bool use_primary = false);
bool isTextAvailable(bool use_primary = false) const;
// Object list management:
// -----------------------
// Clears and adds one single object to the clipboard
bool copyToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE);
// Adds one object to the current list of objects on the clipboard
bool addToClipboard(const LLUUID& src, const LLAssetType::EType type = LLAssetType::AT_NONE);
// Gets a copy of the objects on the clipboard
bool pasteFromClipboard(std::vector<LLUUID>& inventory_objects) const;
bool hasContents() const; // True if the clipboard has pasteable objects
bool isOnClipboard(const LLUUID& object) const; // True if the input object uuid is on the clipboard
bool isCutMode() const { return mCutMode; }
void setCutMode(bool mode) { mCutMode = mode; mGeneration++; }
private:
std::vector<LLUUID> mObjects; // Objects on the clipboard. Can be empty while mString contains something licit (e.g. text from chat)
LLWString mString; // The text string. If mObjects is not empty, this string is reflecting them (UUIDs for the moment) if the asset type is knowable.
bool mCutMode; // This is a convenience flag for the viewer.
int mGeneration; // Incremented when the clipboard changes so that interested parties can check for changes on the clipboard.
};
#endif // LL_LLCLIPBOARD_H
File diff suppressed because it is too large Load Diff
+294
View File
@@ -0,0 +1,294 @@
/**
* @file llcombobox.h
* @brief LLComboBox base class
*
* $LicenseInfo:firstyear=2001&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$
*/
// A control that displays the name of the chosen item, which when clicked
// shows a scrolling box of choices.
#ifndef LL_LLCOMBOBOX_H
#define LL_LLCOMBOBOX_H
#include "llbutton.h"
#include "lluictrl.h"
#include "llctrlselectioninterface.h"
#include "llrect.h"
#include "llscrolllistctrl.h"
#include "lllineeditor.h"
#include <boost/function.hpp>
// Classes
class LLFontGL;
class LLViewBorder;
class LLComboBox
: public LLUICtrl
, public LLCtrlListInterface
, public ll::ui::SearchableControl
{
public:
typedef enum e_preferred_position
{
ABOVE,
BELOW
} EPreferredPosition;
struct PreferredPositionValues : public LLInitParam::TypeValuesHelper<EPreferredPosition, PreferredPositionValues>
{
static void declareValues();
};
struct ItemParams : public LLInitParam::Block<ItemParams, LLScrollListItem::Params>
{
Optional<std::string> label;
ItemParams();
};
struct Params
: public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<bool> allow_text_entry,
show_text_as_tentative,
force_disable_fulltext_search, // <FS:Ansariel> Allow fulltext search in comboboxes
allow_new_values;
Optional<S32> max_chars;
Optional<commit_callback_t> prearrange_callback,
text_entry_callback,
text_changed_callback;
Optional<EPreferredPosition, PreferredPositionValues> list_position;
// components
Optional<LLButton::Params> combo_button;
Optional<LLScrollListCtrl::Params> combo_list;
Optional<LLLineEditor::Params> combo_editor;
Optional<LLButton::Params> drop_down_button;
Multiple<ItemParams> items;
Params();
};
virtual ~LLComboBox();
/*virtual*/ bool postBuild();
protected:
friend class LLUICtrlFactory;
LLComboBox(const Params&);
void initFromParams(const Params&);
void prearrangeList(std::string filter = "");
virtual std::string _getSearchText() const;
virtual void onSetHighlight() const;
void imageLoaded();
public:
// LLView interface
virtual void onFocusLost();
virtual bool handleToolTip(S32 x, S32 y, MASK mask);
virtual bool handleKeyHere(KEY key, MASK mask);
virtual bool handleUnicodeCharHere(llwchar uni_char);
virtual bool handleScrollWheel(S32 x, S32 y, S32 clicks);
// LLUICtrl interface
virtual void clear(); // select nothing
virtual void onCommit();
virtual bool acceptsTextInput() const { return mAllowTextEntry; }
virtual bool isDirty() const; // Returns true if the user has modified this control.
virtual void resetDirty(); // Clear dirty state
virtual void setFocus(bool b);
// Selects item by underlying LLSD value, using LLSD::asString() matching.
// For simple items, this is just the name of the label.
virtual void setValue(const LLSD& value );
// Gets underlying LLSD value for currently selected items. For simple
// items, this is just the label.
virtual LLSD getValue() const;
void setTextEntry(const LLStringExplicit& text);
void setKeystrokeOnEsc(bool enable);
LLScrollListItem* add(const std::string& name, EAddPosition pos = ADD_BOTTOM, bool enabled = true); // add item "name" to menu
LLScrollListItem* add(const std::string& name, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, bool enabled = true);
LLScrollListItem* add(const std::string& name, void* userdata, EAddPosition pos = ADD_BOTTOM, bool enabled = true);
LLScrollListItem* add(const std::string& name, LLSD value, EAddPosition pos = ADD_BOTTOM, bool enabled = true);
LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM);
bool remove( S32 index ); // remove item by index, return true if found and removed
void removeall() { clearRows(); }
bool itemExists(const std::string& name);
LLScrollListItem* getItemByValue(const LLSD& value); // <FS:Ansariel> Get items by value
void sortByName(bool ascending = true); // Sort the entries in the combobox by name
// Select current item by name using selectItemByLabel. Returns false if not found.
bool setSimple(const LLStringExplicit& name);
// Get name of current item. Returns an empty string if not found.
const std::string getSimple() const;
// Get contents of column x of selected row
virtual const std::string getSelectedItemLabel(S32 column = 0) const;
// Sets the label, which doesn't have to exist in the label.
// This is probably a UI abuse.
void setLabel(const LLStringExplicit& name);
// Updates the combobox label to match the selected list item.
void updateLabel();
bool remove(const std::string& name); // remove item "name", return true if found and removed
bool setCurrentByIndex(S32 index);
S32 getCurrentIndex() const;
bool selectNextItem();
bool selectPrevItem();
void setEnabledByValue(const LLSD& value, bool enabled);
void createLineEditor(const Params&);
// <FS:Ansariel> For setting the focus to the LLLineEditor
void focusEditor();
//========================================================================
LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; };
LLCtrlListInterface* getListInterface() { return (LLCtrlListInterface*)this; };
// LLCtrlListInterface functions
// See llscrolllistctrl.h
virtual S32 getItemCount() const;
// Overwrites the default column (See LLScrollListCtrl for format)
virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM);
virtual void clearColumns();
virtual void setColumnLabel(const std::string& column, const std::string& label);
virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL);
virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos = ADD_BOTTOM, const LLSD& id = LLSD());
virtual void clearRows();
virtual void sortByColumn(const std::string& name, bool ascending);
// LLCtrlSelectionInterface functions
virtual bool getCanSelect() const { return true; }
virtual bool selectFirstItem() { return setCurrentByIndex(0); }
virtual bool selectNthItem( S32 index ) { return setCurrentByIndex(index); }
virtual bool selectItemRange( S32 first, S32 last );
virtual S32 getFirstSelectedIndex() const { return getCurrentIndex(); }
virtual bool setCurrentByID( const LLUUID& id );
virtual LLUUID getCurrentID() const; // LLUUID::null if no items in menu
virtual bool setSelectedByValue(const LLSD& value, bool selected);
virtual LLSD getSelectedValue();
virtual bool isSelected(const LLSD& value) const;
virtual bool operateOnSelection(EOperation op);
virtual bool operateOnAll(EOperation op);
//========================================================================
void setLeftTextPadding(S32 pad);
void* getCurrentUserdata();
void setPrearrangeCallback( commit_callback_t cb ) { mPrearrangeCallback = cb; }
void setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; }
void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; }
/**
* Connects callback to signal called when Return key is pressed.
*/
boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); }
void setButtonVisible(bool visible);
void onButtonMouseDown();
void onListMouseUp();
void onItemSelected(const LLSD& data);
void onTextCommit(const LLSD& data);
void updateSelection();
virtual void showList();
virtual void hideList();
virtual void onTextEntry(LLLineEditor* line_editor);
protected:
LLButton* mButton;
LLLineEditor* mTextEntry;
LLScrollListCtrl* mList;
EPreferredPosition mListPosition;
LLPointer<LLUIImage> mArrowImage;
LLUIString mLabel;
bool mHasAutocompletedText;
private:
bool mAllowTextEntry;
bool mAllowNewValues;
S32 mMaxChars;
bool mTextEntryTentative;
commit_callback_t mPrearrangeCallback;
commit_callback_t mTextEntryCallback;
commit_callback_t mTextChangedCallback;
commit_callback_t mSelectionCallback;
boost::signals2::connection mTopLostSignalConnection;
boost::signals2::connection mImageLoadedConnection;
commit_signal_t mOnReturnSignal;
S32 mLastSelectedIndex;
bool mForceDisableFulltextSearch; // <FS:Ansariel> Allow fulltext search in comboboxes
};
// A combo box with icons for the list of items.
class LLIconsComboBox
: public LLComboBox
{
public:
struct Params
: public LLInitParam::Block<Params, LLComboBox::Params>
{
Optional<S32> icon_column,
label_column;
Params();
};
/*virtual*/ const std::string getSelectedItemLabel(S32 column = 0) const;
private:
enum EColumnIndex
{
ICON_COLUMN = 0,
LABEL_COLUMN
};
friend class LLUICtrlFactory;
LLIconsComboBox(const Params&);
virtual ~LLIconsComboBox() {};
S32 mIconColumnIndex;
S32 mLabelColumnIndex;
};
#endif
+197
View File
@@ -0,0 +1,197 @@
/**
* @file llcommandmanager.cpp
* @brief LLCommandManager class
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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$
*/
// A control that displays the name of the chosen item, which when
// clicked shows a scrolling box of options.
#include "linden_common.h"
#include "llcommandmanager.h"
#include "lldir.h"
#include "llerror.h"
#include "llxuiparser.h"
//
// LLCommandId class
//
const LLCommandId LLCommandId::null = LLCommandId("null command");
//
// LLCommand class
//
LLCommand::Params::Params()
: available_in_toybox("available_in_toybox", false)
, icon("icon")
, label_ref("label_ref")
, name("name")
, tooltip_ref("tooltip_ref")
, execute_function("execute_function")
, execute_parameters("execute_parameters")
, execute_stop_function("execute_stop_function")
, execute_stop_parameters("execute_stop_parameters")
, is_enabled_function("is_enabled_function")
, is_enabled_parameters("is_enabled_parameters")
, is_running_function("is_running_function")
, is_running_parameters("is_running_parameters")
, is_starting_function("is_starting_function")
, is_starting_parameters("is_starting_parameters")
, is_flashing_allowed("is_flashing_allowed", false)
, control_name("control_name") // <FS:Zi> Add control_name to toolbar buttons
, checkbox_control("checkbox_control") // <FS:Zi> Add checkbox control toggle
{
}
LLCommand::LLCommand(const LLCommand::Params& p)
: mIdentifier(p.name)
, mAvailableInToybox(p.available_in_toybox)
, mIcon(p.icon)
, mLabelRef(p.label_ref)
, mName(p.name)
, mTooltipRef(p.tooltip_ref)
, mExecuteFunction(p.execute_function)
, mExecuteParameters(p.execute_parameters)
, mExecuteStopFunction(p.execute_stop_function)
, mExecuteStopParameters(p.execute_stop_parameters)
, mIsEnabledFunction(p.is_enabled_function)
, mIsEnabledParameters(p.is_enabled_parameters)
, mIsRunningFunction(p.is_running_function)
, mIsRunningParameters(p.is_running_parameters)
, mIsStartingFunction(p.is_starting_function)
, mIsStartingParameters(p.is_starting_parameters)
, mIsFlashingAllowed(p.is_flashing_allowed)
, mControlVariable(p.control_name) // <FS:Zi> Add control_name to toolbar buttons
, mCheckboxControlVariable(p.checkbox_control) // <FS:Zi> Add checkbox control toggle
{
}
//
// LLCommandManager class
//
LLCommandManager::LLCommandManager()
{
}
LLCommandManager::~LLCommandManager()
{
for (CommandVector::iterator cmdIt = mCommands.begin(); cmdIt != mCommands.end(); ++cmdIt)
{
LLCommand * command = *cmdIt;
delete command;
}
}
U32 LLCommandManager::commandCount() const
{
return static_cast<U32>(mCommands.size());
}
LLCommand * LLCommandManager::getCommand(U32 commandIndex)
{
return mCommands[commandIndex];
}
LLCommand * LLCommandManager::getCommand(const LLCommandId& commandId)
{
LLCommand * command_match = NULL;
CommandIndexMap::const_iterator found = mCommandIndices.find(commandId.uuid());
if (found != mCommandIndices.end())
{
command_match = mCommands[found->second];
}
return command_match;
}
LLCommand * LLCommandManager::getCommand(const std::string& name)
{
LLCommand * command_match = NULL;
CommandVector::const_iterator it = mCommands.begin();
while (it != mCommands.end())
{
if ((*it)->name() == name)
{
command_match = *it;
break;
}
it++;
}
return command_match;
}
void LLCommandManager::addCommand(LLCommand * command)
{
LLCommandId command_id = command->id();
mCommandIndices[command_id.uuid()] = mCommands.size();
mCommands.push_back(command);
LL_DEBUGS() << "Successfully added command: " << command->name() << LL_ENDL;
}
//static
bool LLCommandManager::load()
{
LLCommandManager& mgr = LLCommandManager::instance();
std::string commands_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "commands.xml");
LLCommandManager::Params commandsParams;
LLSimpleXUIParser parser;
if (!parser.readXUI(commands_file, commandsParams))
{
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Unable to load xml file: " << commands_file << LL_ENDL;
return false;
}
if (!commandsParams.validateBlock())
{
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Invalid commands file: " << commands_file << LL_ENDL;
return false;
}
for (const LLCommand::Params& commandParams : commandsParams.commands)
{
LLCommand * command = new LLCommand(commandParams);
mgr.addCommand(command);
}
return true;
}
+225
View File
@@ -0,0 +1,225 @@
/**
* @file llcommandmanager.h
* @brief LLCommandManager class to hold commands
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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_LLCOMMANDMANAGER_H
#define LL_LLCOMMANDMANAGER_H
#include "llinitparam.h"
#include "llsingleton.h"
class LLCommand;
class LLCommandManager;
class LLCommandId
{
public:
friend class LLCommand;
friend class LLCommandManager;
struct Params : public LLInitParam::Block<Params>
{
Mandatory<std::string> name;
Params()
: name("name")
{}
};
LLCommandId(const std::string& name)
{
mUUID = LLUUID::generateNewID(name);
}
LLCommandId(const Params& p)
{
mUUID = LLUUID::generateNewID(p.name);
}
LLCommandId(const LLUUID& uuid)
: mUUID(uuid)
{}
const LLUUID& uuid() const { return mUUID; }
bool operator!=(const LLCommandId& command) const
{
return (mUUID != command.mUUID);
}
bool operator==(const LLCommandId& command) const
{
return (mUUID == command.mUUID);
}
static const LLCommandId null;
private:
LLUUID mUUID;
};
typedef std::list<LLCommandId> command_id_list_t;
class LLCommand
{
public:
struct Params : public LLInitParam::Block<Params>
{
Mandatory<bool> available_in_toybox;
Mandatory<std::string> icon;
Mandatory<std::string> label_ref;
Mandatory<std::string> name;
Mandatory<std::string> tooltip_ref;
// <FS:Zi> Add control_name to toolbar buttons
// so we can have control_name instead of all these functions.
// Mandatory<std::string> execute_function;
Optional<std::string> execute_function;
// </FS:Zi>
Optional<LLSD> execute_parameters;
Optional<std::string> execute_stop_function;
Optional<LLSD> execute_stop_parameters;
Optional<std::string> is_enabled_function;
Optional<LLSD> is_enabled_parameters;
Optional<std::string> is_running_function;
Optional<LLSD> is_running_parameters;
Optional<std::string> is_starting_function;
Optional<LLSD> is_starting_parameters;
Optional<bool> is_flashing_allowed;
Optional<std::string> control_name; // <FS:Zi> Add control_name to toolbar buttons
Optional<std::string> checkbox_control; // <FS:Zi> Add checkbox control toggle
Params();
};
LLCommand(const LLCommand::Params& p);
const bool availableInToybox() const { return mAvailableInToybox; }
const std::string& icon() const { return mIcon; }
const LLCommandId& id() const { return mIdentifier; }
const std::string& labelRef() const { return mLabelRef; }
const std::string& name() const { return mName; }
const std::string& tooltipRef() const { return mTooltipRef; }
const std::string& executeFunctionName() const { return mExecuteFunction; }
const LLSD& executeParameters() const { return mExecuteParameters; }
const std::string& executeStopFunctionName() const { return mExecuteStopFunction; }
const LLSD& executeStopParameters() const { return mExecuteStopParameters; }
const std::string& isEnabledFunctionName() const { return mIsEnabledFunction; }
const LLSD& isEnabledParameters() const { return mIsEnabledParameters; }
const std::string& isRunningFunctionName() const { return mIsRunningFunction; }
const LLSD& isRunningParameters() const { return mIsRunningParameters; }
const std::string& isStartingFunctionName() const { return mIsStartingFunction; }
const LLSD& isStartingParameters() const { return mIsStartingParameters; }
bool isFlashingAllowed() const { return mIsFlashingAllowed; }
private:
LLCommandId mIdentifier;
bool mAvailableInToybox;
std::string mIcon;
std::string mLabelRef;
std::string mName;
std::string mTooltipRef;
std::string mExecuteFunction;
LLSD mExecuteParameters;
std::string mExecuteStopFunction;
LLSD mExecuteStopParameters;
std::string mIsEnabledFunction;
LLSD mIsEnabledParameters;
std::string mIsRunningFunction;
LLSD mIsRunningParameters;
std::string mIsStartingFunction;
LLSD mIsStartingParameters;
bool mIsFlashingAllowed;
// <FS;Zi> Add control_variable ald checkbox_control to commands in toolbar
std::string mControlVariable;
std::string mCheckboxControlVariable;
public:
const std::string& controlVariableName() const { return mControlVariable; }
const std::string& checkboxControlVariableName() const { return mCheckboxControlVariable; }
// </FS:Zi>
};
class LLCommandManager
: public LLSingleton<LLCommandManager>
{
LLSINGLETON(LLCommandManager);
~LLCommandManager();
public:
struct Params : public LLInitParam::Block<Params>
{
Multiple< LLCommand::Params, AtLeast<1> > commands;
Params()
: commands("command")
{
}
};
U32 commandCount() const;
LLCommand * getCommand(U32 commandIndex);
LLCommand * getCommand(const LLCommandId& commandId);
LLCommand * getCommand(const std::string& name);
static bool load();
protected:
void addCommand(LLCommand * command);
private:
typedef std::map<LLUUID, size_t> CommandIndexMap;
typedef std::vector<LLCommand *> CommandVector;
CommandVector mCommands;
CommandIndexMap mCommandIndices;
};
#endif // LL_LLCOMMANDMANAGER_H
+857
View File
@@ -0,0 +1,857 @@
/**
* @file llconsole.cpp
* @brief a scrolling console output device
*
* $LicenseInfo:firstyear=2001&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$
*/
//#include "llviewerprecompiledheaders.h"
#include "linden_common.h"
#include "llconsole.h"
// linden library includes
#include "llmath.h"
//#include "llviewercontrol.h"
#include "llcriticaldamp.h"
#include "llfontgl.h"
#include "llgl.h"
#include "llui.h"
#include "lluiimage.h"
//#include "llviewerimage.h"
//#include "llviewerimagelist.h"
//#include "llviewerwindow.h"
#include "llsd.h"
#include "llfontgl.h"
#include "llmath.h"
#include "llurlregistry.h" // for SLURL parsing
//#include "llstartup.h"
// Used for LCD display
extern void AddNewDebugConsoleToLCD(const LLWString &newLine);
LLConsole* gConsole = NULL; // Created and destroyed in LLViewerWindow.
const F32 FADE_DURATION = 2.f;
static LLDefaultChildRegistry::Register<LLConsole> r("console");
LLConsole::LLConsole(const LLConsole::Params& p)
: LLUICtrl(p),
LLFixedBuffer(p.max_lines),
mLinePersistTime(p.persist_time), // seconds
mFont(p.font),
mConsoleWidth(0),
mConsoleHeight(0),
mParseUrls(p.parse_urls), // <FS:Ansariel> If lines should be parsed for URLs
mSessionSupport(p.session_support) // <FS:Ansariel> Session support
{
if (p.font_size_index.isProvided())
{
setFontSize(p.font_size_index);
}
mFadeTime = mLinePersistTime - FADE_DURATION;
setMaxLines(LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines"));
// <FS:Ansariel> Configurable background for different console types
mBackgroundImage = LLUI::getUIImage(p.background_image);
}
void LLConsole::setLinePersistTime(F32 seconds)
{
mLinePersistTime = seconds;
mFadeTime = mLinePersistTime - FADE_DURATION;
}
void LLConsole::reshape(S32 width, S32 height, bool called_from_parent)
{
S32 new_width = llmax(50, llmin(getRect().getWidth(), width));
S32 new_height = llmax(mFont->getLineHeight() + 15, llmin(getRect().getHeight(), height));
if ( mConsoleWidth == new_width
&& mConsoleHeight == new_height )
{
return;
}
mConsoleWidth = new_width;
mConsoleHeight= new_height;
LLUICtrl::reshape(new_width, new_height, called_from_parent);
for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
{
// <FS:Ansariel> Added styleflags parameter for style customization
//(*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true);
(*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, (*paragraph_it).mLines.front().mStyleFlags, true);
// </FS:Ansariel>
}
}
void LLConsole::setFontSize(S32 size_index)
{
if (-1 == size_index)
{
mFont = LLFontGL::getFontMonospace();
}
else if (0 == size_index)
{
// <FS>
//mFont = LLFontGL::getFontSansSerif();
mFont = LLFontGL::getFontSansSerifSmall();
// </FS>
}
else if (1 == size_index)
{
// <FS>
//mFont = LLFontGL::getFontSansSerifBig();
mFont = LLFontGL::getFontSansSerif();
// </FS>
}
// <FS>
else if (2 == size_index)
{
mFont = LLFontGL::getFontSansSerifBig();
}
// </FS>
else
{
mFont = LLFontGL::getFontSansSerifHuge();
}
// Make sure the font exists
if (mFont == NULL)
{
mFont = LLFontGL::getFontDefault();
}
for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
{
// <FSAnsariel> Added styleflags parameter for style customization
//(*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true);
(*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, (*paragraph_it).mLines.front().mStyleFlags, true);
// </FS:Ansariel>
}
}
void LLConsole::draw()
{
// Units in pixels
// <FS>
//static const F32 padding_horizontal = 10;
//static const F32 padding_vertical = 3;
constexpr F32 padding_horizontal = 15;
constexpr F32 padding_vertical = 8;
// </FS>
LLGLSUIDefault gls_ui;
// skip lines added more than mLinePersistTime ago
F32 cur_time = mTimer.getElapsedTimeF32();
F32 skip_time = cur_time - mLinePersistTime;
F32 fade_time = cur_time - mFadeTime;
if (mParagraphs.empty()) //No text to draw.
{
return;
}
// <FS:minerjr> [FIRE-35039] Add flag to show/hide the on-screen console
// Get the Show On-screen Console flag from the Comm menu
static LLUICachedControl<bool> showOnscreenConsole("FSShowOnscreenConsole");
// If the Show On-screen Console flag is disabled and the current console is the global console
// (Not a debug console), then don't try to draw
if (!showOnscreenConsole && this == gConsole)
{
return;
}
// </FS:minerjr> [FIRE-35039]
// <FS:Ansariel> Session support
if (!mSessionSupport)
{
// This is done in update() if session support is enabled
// </FS:Ansariel>
size_t num_lines{ 0 };
paragraph_t::reverse_iterator paragraph_it;
paragraph_it = mParagraphs.rbegin();
auto paragraph_num=mParagraphs.size();
while (!mParagraphs.empty() && paragraph_it != mParagraphs.rend())
{
num_lines += (*paragraph_it).mLines.size();
if(num_lines > mMaxLines
|| ( (mLinePersistTime > (F32)0.f) && ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime) <= (F32)0.f))
{ //All lines above here are done. Lose them.
for (size_t i = 0; i < paragraph_num; i++)
{
if (!mParagraphs.empty())
mParagraphs.pop_front();
}
break;
}
paragraph_num--;
paragraph_it++;
}
// <FS:Ansariel> Session support
}
// </FS:Ansariel>
if (mParagraphs.empty())
{
return;
}
// draw remaining lines
//[FIX FIRE-2822 SJ] Start a little bit higher with the Console not to let it blend with the stand button when Avatar is sitting
//F32 y_pos = 0.f;
F32 y_pos = 10.f;
// <FS> Different draw options
//LLUIImagePtr imagep = LLUI::getUIImage("transparent");
//static LLCachedControl<F32> console_bg_opacity(*LLUI::getInstance()->mSettingGroups["config"], "ConsoleBackgroundOpacity", 0.7f);
//F32 console_opacity = llclamp(console_bg_opacity(), 0.f, 1.f);
//static LLUIColor color = LLUIColorTable::instance().getColor("ConsoleBackground");
//color.mV[VALPHA] *= console_opacity;
//F32 line_height = (F32)mFont->getLineHeight();
//for(paragraph_it = mParagraphs.rbegin(); paragraph_it != mParagraphs.rend(); paragraph_it++)
//{
// S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + padding_vertical);
// S32 target_width = llfloor( (*paragraph_it).mMaxWidth + padding_horizontal);
// y_pos += ((*paragraph_it).mLines.size()) * line_height;
// imagep->drawSolid(-14, (S32)(y_pos + line_height - target_height), target_width, target_height, color);
// F32 y_off=0;
// F32 alpha;
// if ((mLinePersistTime > 0.f) && ((*paragraph_it).mAddTime < fade_time))
// {
// alpha = ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime);
// }
// else
// {
// alpha = 1.0f;
// }
// if( alpha > 0.f )
// {
// for (lines_t::iterator line_it=(*paragraph_it).mLines.begin();
// line_it != (*paragraph_it).mLines.end();
// line_it ++)
// {
// for (line_color_segments_t::iterator seg_it = (*line_it).mLineColorSegments.begin();
// seg_it != (*line_it).mLineColorSegments.end();
// seg_it++)
// {
// mFont->render((*seg_it).mText, 0, (*seg_it).mXPosition - 8, y_pos - y_off,
// LLColor4(
// (*seg_it).mColor.mV[VRED],
// (*seg_it).mColor.mV[VGREEN],
// (*seg_it).mColor.mV[VBLUE],
// (*seg_it).mColor.mV[VALPHA]*alpha),
// LLFontGL::LEFT,
// LLFontGL::BASELINE,
// LLFontGL::NORMAL,
// LLFontGL::DROP_SHADOW,
// S32_MAX,
// target_width
// );
// }
// y_off += line_height;
// }
// }
// y_pos += padding_vertical;
//}
paragraph_t::reverse_iterator paragraph_it;
static LLCachedControl<F32> consoleBackgroundOpacity(*LLUI::getInstance()->mSettingGroups["config"], "ConsoleBackgroundOpacity");
static LLUIColor cbcolor = LLUIColorTable::instance().getColor("ConsoleBackground");
LLColor4 color = cbcolor.get();
color.mV[VALPHA] *= llclamp(consoleBackgroundOpacity(), 0.f, 1.f);
F32 line_height = (F32)mFont->getLineHeight();
static LLCachedControl<bool> classic_draw_mode(*LLUI::getInstance()->mSettingGroups["config"], "FSConsoleClassicDrawMode");
if (classic_draw_mode)
{
constexpr F32 padding_vert = 5.f;
S32 total_width = 0;
S32 total_height = 0;
size_t lines_drawn = 0;
paragraph_t::reverse_iterator paragraphs_end = mParagraphs.rend();
for (paragraph_it = mParagraphs.rbegin(); paragraph_it != paragraphs_end; ++paragraph_it)
{
if (mSessionSupport)
{
// Skip paragraph if visible in floater and make sure we don't
// exceed the maximum number of lines we want to display
if (mCurrentSessions.find((*paragraph_it).mSessionID) != mCurrentSessions.end())
{
continue;
}
lines_drawn += (*paragraph_it).mLines.size();
if (lines_drawn > mMaxLines)
{
break;
}
}
total_height += llfloor( (*paragraph_it).mLines.size() * line_height + padding_vert);
total_width = llmax(total_width, llfloor( (*paragraph_it).mMaxWidth + padding_horizontal));
}
mBackgroundImage->drawSolid(-14, (S32)(y_pos + line_height / 2), total_width, total_height + (S32)((line_height - padding_vert) / 2.f), color);
lines_drawn = 0;
for (paragraph_it = mParagraphs.rbegin(); paragraph_it != paragraphs_end; ++paragraph_it)
{
if (mSessionSupport)
{
// Skip paragraph if visible in floater and make sure we don't
// exceed the maximum number of lines we want to display
if (mCurrentSessions.find((*paragraph_it).mSessionID) != mCurrentSessions.end())
{
continue;
}
lines_drawn += (*paragraph_it).mLines.size();
if (lines_drawn > mMaxLines)
{
break;
}
}
F32 y_off=0;
F32 alpha;
S32 target_width = llfloor( (*paragraph_it).mMaxWidth + padding_horizontal);
y_pos += ((*paragraph_it).mLines.size()) * line_height;
if ((mLinePersistTime > 0.f) && ((*paragraph_it).mAddTime < fade_time))
{
alpha = ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime);
}
else
{
alpha = 1.0f;
}
if( alpha > 0.f )
{
LLConsole::lines_t::iterator lines_end_it = (*paragraph_it).mLines.end();
for (lines_t::iterator line_it=(*paragraph_it).mLines.begin();
line_it != lines_end_it;
++line_it)
{
line_color_segments_t::iterator line_color_segement_end_it = (*line_it).mLineColorSegments.end();
for (line_color_segments_t::iterator seg_it = (*line_it).mLineColorSegments.begin();
seg_it != line_color_segement_end_it;
++seg_it)
{
mFont->render((*seg_it).mText, 0, (*seg_it).mXPosition - 8, y_pos - y_off,
LLColor4(
(*seg_it).mColor.mV[VRED],
(*seg_it).mColor.mV[VGREEN],
(*seg_it).mColor.mV[VBLUE],
(*seg_it).mColor.mV[VALPHA]*alpha),
LLFontGL::LEFT,
LLFontGL::BASELINE,
(*line_it).mStyleFlags,
LLFontGL::DROP_SHADOW,
S32_MAX,
target_width
);
}
y_off += line_height;
}
}
y_pos += padding_vert;
}
}
else
{
size_t lines_drawn = 0;
paragraph_t::reverse_iterator paragraphs_end = mParagraphs.rend();
for(paragraph_it = mParagraphs.rbegin(); paragraph_it != paragraphs_end; paragraph_it++)
{
if (mSessionSupport)
{
// Skip paragraph if visible in floater and make sure we don't
// exceed the maximum number of lines we want to display
if (mCurrentSessions.find((*paragraph_it).mSessionID) != mCurrentSessions.end())
{
continue;
}
lines_drawn += (*paragraph_it).mLines.size();
if (lines_drawn > mMaxLines)
{
break;
}
}
S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + padding_vertical);
S32 target_width = llfloor( (*paragraph_it).mMaxWidth + padding_horizontal);
y_pos += ((*paragraph_it).mLines.size()) * line_height;
mBackgroundImage->drawSolid(-14, (S32)(y_pos + line_height - target_height), target_width, target_height, color);
F32 y_off=0;
F32 alpha;
if ((mLinePersistTime > 0.f) && ((*paragraph_it).mAddTime < fade_time))
{
alpha = ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime);
}
else
{
alpha = 1.0f;
}
if( alpha > 0.f )
{
LLConsole::lines_t::iterator lines_end_it = (*paragraph_it).mLines.end();
for (lines_t::iterator line_it=(*paragraph_it).mLines.begin();
line_it != lines_end_it;
++line_it)
{
line_color_segments_t::iterator line_color_segement_end_it = (*line_it).mLineColorSegments.end();
for (line_color_segments_t::iterator seg_it = (*line_it).mLineColorSegments.begin();
seg_it != line_color_segement_end_it;
++seg_it)
{
mFont->render((*seg_it).mText, 0, (*seg_it).mXPosition - 8, y_pos - y_off,
LLColor4(
(*seg_it).mColor.mV[VRED],
(*seg_it).mColor.mV[VGREEN],
(*seg_it).mColor.mV[VBLUE],
(*seg_it).mColor.mV[VALPHA]*alpha),
LLFontGL::LEFT,
LLFontGL::BASELINE,
(*line_it).mStyleFlags,
LLFontGL::DROP_SHADOW,
S32_MAX,
target_width
);
}
y_off += line_height;
}
}
y_pos += padding_vertical;
}
}
// </FS>
}
// <FS:Ansariel> Chat console
void LLConsole::addConsoleLine(const std::string& utf8line, const LLColor4 &color, const LLUUID& session_id, LLFontGL::StyleFlags styleflags)
{
LLWString wline = utf8str_to_wstring(utf8line);
addConsoleLine(wline, color, session_id, styleflags);
}
void LLConsole::addConsoleLine(const LLWString& wline, const LLColor4 &color, const LLUUID& session_id, LLFontGL::StyleFlags styleflags)
{
if (wline.empty())
{
return;
}
if (!mSessionSupport)
{
removeExtraLines();
}
mMutex.lock();
mLines.push_back(wline);
mLineLengths.push_back((S32)wline.length());
mAddTimes.push_back(mTimer.getElapsedTimeF32());
mLineColors.push_back(color);
mLineStyle.push_back(styleflags);
mSessionIDs.push_back(session_id);
mMutex.unlock();
}
void LLConsole::clear()
{
LL_INFOS() << "Clearing Console..." << LL_ENDL;
mMutex.lock();
mLines.clear();
mAddTimes.clear();
mLineLengths.clear();
mLineColors.clear();
mLineStyle.clear();
mSessionIDs.clear();
mMutex.unlock();
mTimer.reset();
}
void LLConsole::removeExtraLines()
{
mMutex.lock();
while ((S32)mLines.size() > llmax((S32)0, (S32)(mMaxLines - 1)))
{
mLines.pop_front();
mAddTimes.pop_front();
mLineLengths.pop_front();
if (!mLineColors.empty())
{
mLineColors.pop_front();
}
if (!mLineStyle.empty())
{
mLineStyle.pop_front();
}
}
mMutex.unlock();
}
// </FS:Ansariel> Chat console
//Generate highlight color segments for this paragraph. Pass in default color of paragraph.
void LLConsole::Paragraph::makeParagraphColorSegments (const LLColor4 &color)
{
LLSD paragraph_color_segments;
paragraph_color_segments[0]["text"] =wstring_to_utf8str(mParagraphText);
LLSD color_sd = color.getValue();
paragraph_color_segments[0]["color"]=color_sd;
for(LLSD::array_const_iterator color_segment_it = paragraph_color_segments.beginArray();
color_segment_it != paragraph_color_segments.endArray();
++color_segment_it)
{
LLSD color_llsd = (*color_segment_it)["color"];
std::string color_str = (*color_segment_it)["text"].asString();
ParagraphColorSegment color_segment;
color_segment.mColor.setValue(color_llsd);
color_segment.mNumChars = static_cast<S32>(color_str.length());
mParagraphColorSegments.push_back(color_segment);
}
}
//Called when a paragraph is added to the console or window is resized.
// <FS:Ansariel> Added styleflags parameter for style customization
//void LLConsole::Paragraph::updateLines(F32 screen_width, const LLFontGL* font, bool force_resize)
void LLConsole::Paragraph::updateLines(F32 screen_width, const LLFontGL* font, LLFontGL::StyleFlags styleflags, bool force_resize)
// </FS:Ansariel>
{
if ( !force_resize )
{
// <FS:minerjr> [FIRE-35081] Blurry prims not changing with graphics settings
// if ( mMaxWidth >= 0.0f
//&& mMaxWidth < screen_width)
// If viewer window was made as small as possible with the console enabled, it would cause an assert error
// as the line below can go as small as -38
if ( ((mMaxWidth >= 0.0f) && (mMaxWidth < screen_width)) || (screen_width <= 30) )
// </FS:minerjr> [FIRE-35081]
{
return; //No resize required.
}
}
screen_width = screen_width - 30; //Margin for small windows.
if ( mParagraphText.empty()
|| mParagraphColorSegments.empty()
|| font == NULL)
{
return; //Not enough info to complete.
}
mLines.clear(); //Chuck everything.
mMaxWidth = 0.0f;
paragraph_color_segments_t::iterator current_color = mParagraphColorSegments.begin();
U32 current_color_length = (*current_color).mNumChars;
S32 paragraph_offset = 0; //Offset into the paragraph text.
// Wrap lines that are longer than the view is wide.
while( paragraph_offset < (S32)mParagraphText.length() &&
mParagraphText[paragraph_offset] != 0)
{
// <FS> FIRE-8257: Sometimes text is cut off on left side of console
//S32 skip_chars; // skip '\n'
// Figure out if a word-wrapped line fits here.
LLWString::size_type line_end = mParagraphText.find_first_of(llwchar('\n'), paragraph_offset);
// <FS> FIRE-8257: Sometimes text is cut off on left side of console
//if (line_end != LLWString::npos)
//{
// skip_chars = 1; // skip '\n'
//}
//else
//{
// line_end = mParagraphText.size();
// skip_chars = 0;
//}
//U32 drawable = font->maxDrawableChars(mParagraphText.c_str()+paragraph_offset, screen_width, static_cast<S32>(line_end) - paragraph_offset, LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
if (line_end == LLWString::npos)
{
line_end = mParagraphText.size();
}
S32 skip_chars = 0; // skip '\n'
U32 line_length = static_cast<U32>(line_end) - paragraph_offset;
U32 drawable = font->maxDrawableChars(mParagraphText.c_str()+paragraph_offset, screen_width, line_length, LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);
// </FS>
if (drawable != 0)
{
// <FS> FIRE-8257: Sometimes text is cut off on left side of console
if (drawable >= line_length)
{
skip_chars = 1;
}
// </FS>
F32 x_position = 0; //Screen X position of text.
mMaxWidth = llmax( mMaxWidth, (F32)font->getWidth( mParagraphText.substr( paragraph_offset, drawable ).c_str() ) );
Line line;
line.mStyleFlags = styleflags; // <FS:Ansariel> Add styleflags to every new line
U32 left_to_draw = drawable;
U32 drawn = 0;
while (left_to_draw >= current_color_length
&& current_color != mParagraphColorSegments.end() )
{
LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, current_color_length );
line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line.
(*current_color).mColor,
x_position ) );
x_position += font->getWidth( color_text.c_str() ); //Set up next screen position.
drawn += current_color_length;
left_to_draw -= current_color_length;
current_color++; //Goto next paragraph color record.
if (current_color != mParagraphColorSegments.end())
{
current_color_length = (*current_color).mNumChars;
}
}
if (left_to_draw > 0 && current_color != mParagraphColorSegments.end() )
{
LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, left_to_draw );
line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line.
(*current_color).mColor,
x_position ) );
current_color_length -= left_to_draw;
}
mLines.push_back(line); //Append line to paragraph line list.
}
// <FS> FIRE-8257: Sometimes text is cut off on left side of console
else
{
mLines.push_back(Line());
skip_chars = 1;
}
// </FS>
paragraph_offset += (drawable + skip_chars);
}
}
//Pass in the string and the default color for this block of text.
// <FS:Ansariel> Added styleflags parameter for style customization and session support
//LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width)
//: mParagraphText(str), mAddTime(add_time), mMaxWidth(-1)
LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width, LLFontGL::StyleFlags styleflags, const LLUUID& session_id, bool parse_urls, LLConsole* console)
: mParagraphText(str), mAddTime(add_time), mMaxWidth(-1), mSessionID(session_id)
// </FS:Ansariel>
{
// <FS:Ansariel> Parse SLURLs
mSourceText = str;
mID.generate();
if (parse_urls)
{
LLUrlMatch urlMatch;
LLWString workLine = str;
while (LLUrlRegistry::instance().findUrl(workLine, urlMatch, boost::bind(&LLConsole::onUrlLabelCallback, console, mID, _1, _2)) && !urlMatch.getUrl().empty())
{
// Special case for LLUrlEntryHTTP, LLUrlEntryHTTPNoProtocol and
// LLUrlEntrySecondlifeURL: getLabel() only returns host part, but
// we also want the query part
std::string label = urlMatch.getLabel();
std::string query = urlMatch.getQuery();
if (!query.empty())
{
label += query;
}
// This works for LLUrlEntryHTTPLabel and LLUrlEntrySLLabel because
// there is no callback involved for which we are storing the
// matched Url
LLWStringUtil::replaceString(mParagraphText, utf8str_to_wstring(urlMatch.getMatchedText()), utf8str_to_wstring(label));
mUrlLabels[urlMatch.getUrl()] = label;
// Remove the URL from the work line so we don't end in a loop in case of regular URLs!
// findUrl will always return the very first URL in a string
workLine = workLine.erase(0, urlMatch.getEnd() + 1);
}
}
// </FS:Ansariel>
makeParagraphColorSegments(color);
// <FS:Ansariel> Added styleflags parameter for style customization
//updateLines( screen_width, font );
updateLines( screen_width, font, styleflags );
// </FS:Ansariel>
}
// <FS:Ansariel> Parse SLURLs
void LLConsole::onUrlLabelCallback(const LLUUID& paragraph_id, const std::string& url, const std::string& label)
{
for (paragraph_t::reverse_iterator it = mParagraphs.rbegin(); it != mParagraphs.rend(); ++it)
{
LLConsole::Paragraph& paragraph = *it;
if (paragraph.mID == paragraph_id)
{
paragraph.mUrlLabels[url] = label;
LLWString newText = paragraph.mSourceText;
for (std::map<std::string, std::string>::iterator url_it = paragraph.mUrlLabels.begin(); url_it != paragraph.mUrlLabels.end(); ++url_it)
{
LLWStringUtil::replaceString(newText, utf8string_to_wstring(url_it->first), utf8string_to_wstring(url_it->second));
}
paragraph.mParagraphText = newText;
paragraph.makeParagraphColorSegments(paragraph.mLines.front().mLineColorSegments.front().mColor);
paragraph.updateLines((F32)getRect().getWidth(), mFont, paragraph.mLines.front().mStyleFlags, true);
break;
}
}
}
// </FS:Ansariel>
// called once per frame regardless of console visibility
// static
void LLConsole::updateClass()
{
for (auto& con : instance_snapshot())
{
con.update();
}
}
static LLTrace::BlockTimerStatHandle FTM_CONSOLE_UPDATE_PARAGRAPHS("Update Console Paragraphs");
void LLConsole::update()
{
{
LLCoros::LockType lock(mMutex);
while (!mLines.empty())
{
// <FS:Ansariel> Chat console
//mParagraphs.push_back(
// Paragraph( mLines.front(),
// LLColor4::white,
// mTimer.getElapsedTimeF32(),
// mFont,
// (F32)getRect().getWidth()));
//mLines.pop_front();
mParagraphs.push_back(
Paragraph( mLines.front(),
(!mLineColors.empty() ? mLineColors.front() : LLColor4::white),
mTimer.getElapsedTimeF32(),
mFont,
(F32)getRect().getWidth(),
(!mLineStyle.empty() ? mLineStyle.front() : LLFontGL::NORMAL),
(!mSessionIDs.empty() ? mSessionIDs.front(): LLUUID::null),
mParseUrls,
this));
mLines.pop_front();
if (!mLineColors.empty())
mLineColors.pop_front();
if (!mLineStyle.empty())
mLineStyle.pop_front();
if (!mSessionIDs.empty())
mSessionIDs.pop_front();
// </FS:Ansariel>
}
}
// remove old paragraphs which can't possibly be visible any more. ::draw() will do something similar but more conservative - we do this here because ::draw() isn't guaranteed to ever be called! (i.e. the console isn't visible)
// <FS:Ansariel> Session support
if (!mSessionSupport)
{
// </FS:Ansariel>
while ((S32)mParagraphs.size() > llmax((S32)0, (S32)(mMaxLines)))
{
mParagraphs.pop_front();
}
// <FS:Ansariel> Session support
}
else
{
LL_RECORD_BLOCK_TIME(FTM_CONSOLE_UPDATE_PARAGRAPHS);
// skip lines added more than mLinePersistTime ago
F32 skip_time = mTimer.getElapsedTimeF32() - mLinePersistTime;
paragraph_t temp_para;
std::map<LLUUID, U32> session_map;
for (paragraph_t::reverse_iterator it = mParagraphs.rbegin(); it != mParagraphs.rend(); ++it)
{
Paragraph& para = *it;
session_map[para.mSessionID] += (U32)para.mLines.size();
if (session_map[para.mSessionID] <= mMaxLines && // max lines on a per session basis
!((mLinePersistTime > 0.f) && (para.mAddTime - skip_time) / (mLinePersistTime - mFadeTime) <= 0.f)) // not expired yet
{
temp_para.push_front(para);
}
}
mParagraphs.swap(temp_para);
}
// </FS:Ansariel>
}
// <FS:Ansariel> Session support
void LLConsole::addSession(const LLUUID& session_id)
{
mCurrentSessions.insert(session_id);
}
void LLConsole::removeSession(const LLUUID& session_id)
{
mCurrentSessions.erase(session_id);
}
// </FS:Ansariel>
+200
View File
@@ -0,0 +1,200 @@
/**
* @file llconsole.h
* @brief a simple console-style output device
*
* $LicenseInfo:firstyear=2001&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_LLCONSOLE_H
#define LL_LLCONSOLE_H
#include "llfixedbuffer.h"
#include "lluictrl.h"
#include "v4color.h"
#include <deque>
class LLSD;
class LLConsole : public LLFixedBuffer, public LLUICtrl, public LLInstanceTracker<LLConsole>
{
public:
typedef enum e_font_size
{
MONOSPACE = -1,
SMALL = 0,
BIG = 1
} EFontSize;
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<U32> max_lines;
Optional<F32> persist_time;
Optional<S32> font_size_index;
Optional<bool> parse_urls; // <FS:Ansariel> If lines should be parsed for URLs
Optional<std::string> background_image; // <FS:Ansariel> Configurable background for different console types
Optional<bool> session_support; // <FS:Ansariel> Session support
Params()
: max_lines("max_lines", LLUI::getInstance()->mSettingGroups["config"]->getS32("ConsoleMaxLines")),
persist_time("persist_time", 0.f), // forever
font_size_index("font_size_index"),
parse_urls("parse_urls", false), // <FS:Ansariel> If lines should be parsed for URLs
background_image("background_image", "Console_Background"), // <FS:Ansariel> Configurable background for different console types
session_support("session_support", false) // <FS:Ansariel> Session support
{
changeDefault(mouse_opaque, false);
}
};
protected:
LLConsole(const Params&);
friend class LLUICtrlFactory;
public:
// call once per frame to pull data out of LLFixedBuffer
static void updateClass();
//A paragraph color segment defines the color of text in a line
//of text that was received for console display. It has no
//notion of line wraps, screen position, or the text it contains.
//It is only the number of characters that are a color and the
//color.
struct ParagraphColorSegment
{
S32 mNumChars;
LLColor4 mColor;
};
//A line color segment is a chunk of text, the color associated
//with it, and the X Position it was calculated to begin at
//on the screen. X Positions are re-calculated if the
//screen changes size.
class LineColorSegment
{
public:
LineColorSegment(LLWString text, LLColor4 color, F32 xpos) : mText(text), mColor(color), mXPosition(xpos) {}
public:
LLWString mText;
LLColor4 mColor;
F32 mXPosition;
};
typedef std::list<LineColorSegment> line_color_segments_t;
//A line is composed of one or more color segments.
class Line
{
public:
line_color_segments_t mLineColorSegments;
// <FS:Ansariel> Added styleflags member for fontstyle customization
LLFontGL::StyleFlags mStyleFlags;
};
typedef std::list<Line> lines_t;
typedef std::list<ParagraphColorSegment> paragraph_color_segments_t;
//A paragraph is a processed element containing the entire text of the
//message (used for recalculating positions on screen resize)
//The time this message was added to the console output
//The visual screen width of the longest line in this block
//And a list of one or more lines which are used to display this message.
class Paragraph
{
public:
// <FS:Ansariel> Added styleflags parameter for style customization
//Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width);
Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width, LLFontGL::StyleFlags styleflags, const LLUUID& session_id, bool parse_urls, LLConsole* console);
// </FS:Ansariel>
void makeParagraphColorSegments ( const LLColor4 &color);
// <FS:Ansariel> Added styleflags parameter for style customization
//void updateLines ( F32 screen_width, const LLFontGL* font, bool force_resize=false );
void updateLines ( F32 screen_width, const LLFontGL* font, LLFontGL::StyleFlags styleflags, bool force_resize=false );
// </FS:Ansariel>
public:
LLWString mParagraphText; //The entire text of the paragraph
paragraph_color_segments_t mParagraphColorSegments;
F32 mAddTime; //Time this paragraph was added to the display.
F32 mMaxWidth; //Width of the widest line of text in this paragraph.
lines_t mLines;
LLUUID mSessionID; // <FS:Ansariel> Session support
// <FS:Ansariel> Parse SLURLs
LLUUID mID;
LLWString mSourceText;
std::map<std::string, std::string> mUrlLabels;
// </FS:Ansariel>
};
//The console contains a deque of paragraphs which represent the individual messages.
typedef std::deque<Paragraph> paragraph_t;
paragraph_t mParagraphs;
~LLConsole(){};
// each line lasts this long after being added
void setLinePersistTime(F32 seconds);
void reshape(S32 width, S32 height, bool called_from_parent = true);
// -1 = monospace, 0 means small, font size = 1 means big
void setFontSize(S32 size_index);
// Overrides
/*virtual*/ void draw();
// <FS:Ansariel> Chat console
void addConsoleLine(const std::string& utf8line, const LLColor4 &color, const LLUUID& session_id = LLUUID::null, LLFontGL::StyleFlags styleflags = LLFontGL::NORMAL);
void addConsoleLine(const LLWString& wline, const LLColor4 &color, const LLUUID& session_id = LLUUID::null, LLFontGL::StyleFlags styleflags = LLFontGL::NORMAL);
void clear();
void addSession(const LLUUID& session_id);
void removeSession(const LLUUID& session_id);
std::deque<LLColor4> mLineColors;
std::deque<LLFontGL::StyleFlags> mLineStyle;
std::deque<LLUUID> mSessionIDs;
protected:
/*virtual*/ void removeExtraLines();
void onUrlLabelCallback(const LLUUID& paragraph_id, const std::string& url, const std::string& label);
// </FS:Ansariel>
private:
void update();
F32 mLinePersistTime; // Age at which to stop drawing.
F32 mFadeTime; // Age at which to start fading
const LLFontGL* mFont;
S32 mConsoleWidth;
S32 mConsoleHeight;
bool mParseUrls; // <FS:Ansariel> If lines should be parsed for URLs
LLUIImagePtr mBackgroundImage; // <FS:Ansariel> Configurable background for different console types
// <FS:Ansariel> Session support
std::set<LLUUID> mCurrentSessions;
bool mSessionSupport;
// </FS:Ansariel>
};
extern LLConsole* gConsole;
#endif
+308
View File
@@ -0,0 +1,308 @@
/**
* @file llcontainerview.cpp
* @brief Container for all statistics info
*
* $LicenseInfo:firstyear=2001&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$
*/
#include "linden_common.h"
#include "llcontainerview.h"
#include "llerror.h"
#include "llfontgl.h"
#include "llgl.h"
#include "llui.h"
#include "llstring.h"
#include "llscrollcontainer.h"
#include "lluictrlfactory.h"
static LLDefaultChildRegistry::Register<LLContainerView> r1("container_view");
#include "llpanel.h"
#include "llstatview.h"
static ContainerViewRegistry::Register<LLStatView> r2("stat_view");
static ContainerViewRegistry::Register<LLPanel> r3("panel", &LLPanel::fromXML);
LLContainerView::LLContainerView(const LLContainerView::Params& p)
: LLView(p),
mShowLabel(p.show_label),
mLabel(utf8str_to_wstring(p.label)),
// <FS:Zi> Add background visible flag and color to container_view so we can have blank scrollview containers
mBackgroundVisible(p.background_visible),
mBackgroundColor(p.bg_color),
// </FS:Zi>
mDisplayChildren(p.display_children)
{
mScrollContainer = NULL;
}
LLContainerView::~LLContainerView()
{
// Children all cleaned up by default view destructor.
}
bool LLContainerView::postBuild()
{
setDisplayChildren(mDisplayChildren);
reshape(getRect().getWidth(), getRect().getHeight(), false);
return true;
}
bool LLContainerView::addChild(LLView* child, S32 tab_group)
{
bool res = LLView::addChild(child, tab_group);
if (res)
{
sendChildToBack(child);
}
return res;
}
bool LLContainerView::handleDoubleClick(S32 x, S32 y, MASK mask)
{
return handleMouseDown(x, y, mask);
}
bool LLContainerView::handleMouseDown(S32 x, S32 y, MASK mask)
{
bool handled = false;
if (mDisplayChildren)
{
handled = (LLView::childrenHandleMouseDown(x, y, mask) != NULL);
}
if (!handled)
{
if( mShowLabel && (y >= getRect().getHeight() - 10) )
{
setDisplayChildren(!mDisplayChildren);
reshape(getRect().getWidth(), getRect().getHeight(), false);
handled = true;
}
}
return handled;
}
bool LLContainerView::handleMouseUp(S32 x, S32 y, MASK mask)
{
bool handled = false;
if (mDisplayChildren)
{
handled = (LLView::childrenHandleMouseUp(x, y, mask) != NULL);
}
return handled;
}
void LLContainerView::draw()
{
// <FS:Zi> Add background visible flag and color to container_view so we can have blank scrollview containers
if (mBackgroundVisible)
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// <FS:Zi> Add background visible flag and color to container_view so we can have blank scrollview containers
// gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor);
}
// Draw the label
if (mShowLabel)
{
LLFontGL::getFontMonospace()->render(
mLabel, 0, 2.f, (F32)(getRect().getHeight() - 2), LLColor4(1,1,1,1), LLFontGL::LEFT, LLFontGL::TOP);
}
LLView::draw();
}
void LLContainerView::reshape(S32 width, S32 height, bool called_from_parent)
{
LLRect scroller_rect;
scroller_rect.setOriginAndSize(0, 0, width, height);
if (mScrollContainer)
{
scroller_rect = mScrollContainer->getContentWindowRect();
}
else
{
// if we're uncontained - make height as small as possible
scroller_rect.mTop = 0;
}
arrange(scroller_rect.getWidth(), scroller_rect.getHeight(), called_from_parent);
// sometimes, after layout, our container will change size (scrollbars popping in and out)
// if so, attempt another layout
if (mScrollContainer)
{
LLRect new_container_rect = mScrollContainer->getContentWindowRect();
if ((new_container_rect.getWidth() != scroller_rect.getWidth()) ||
(new_container_rect.getHeight() != scroller_rect.getHeight())) // the container size has changed, attempt to arrange again
{
arrange(new_container_rect.getWidth(), new_container_rect.getHeight(), called_from_parent);
}
}
}
void LLContainerView::arrange(S32 width, S32 height, bool called_from_parent)
{
// Determine the sizes and locations of all contained views
S32 total_height = 0;
S32 top, left, right, bottom;
//LLView *childp;
// These will be used for the children
left = 10;
top = getRect().getHeight() - 4;
right = width - 2;
bottom = top;
// Leave some space for the top label/grab handle
if (mShowLabel)
{
total_height += 20;
}
if (mDisplayChildren)
{
// Determine total height
U32 child_height = 0;
for (child_list_const_iter_t child_iter = getChildList()->begin();
child_iter != getChildList()->end(); ++child_iter)
{
LLView *childp = *child_iter;
if (!childp->getVisible())
{
LL_WARNS() << "Incorrect visibility!" << LL_ENDL;
}
LLRect child_rect = childp->getRequiredRect();
child_height += child_rect.getHeight();
child_height += 2;
}
total_height += child_height;
}
if (total_height < height)
total_height = height;
LLRect my_rect = getRect();
if (followsTop())
{
my_rect.mBottom = my_rect.mTop - total_height;
}
else
{
my_rect.mTop = my_rect.mBottom + total_height;
}
my_rect.mRight = my_rect.mLeft + width;
setRect(my_rect);
top = total_height;
if (mShowLabel)
{
top -= 20;
}
bottom = top;
if (mDisplayChildren)
{
// Iterate through all children, and put in container from top down.
for (child_list_const_iter_t child_iter = getChildList()->begin();
child_iter != getChildList()->end(); ++child_iter)
{
LLView *childp = *child_iter;
LLRect child_rect = childp->getRequiredRect();
bottom -= child_rect.getHeight();
LLRect r(left, bottom + child_rect.getHeight(), right, bottom);
childp->setRect(r);
childp->reshape(right - left, top - bottom);
top = bottom - 2;
bottom = top;
}
}
if (!called_from_parent)
{
if (getParent())
{
getParent()->reshape(getParent()->getRect().getWidth(), getParent()->getRect().getHeight(), false);
}
}
}
LLRect LLContainerView::getRequiredRect()
{
LLRect req_rect;
//LLView *childp;
U32 total_height = 0;
// Determine the sizes and locations of all contained views
// Leave some space for the top label/grab handle
if (mShowLabel)
{
total_height = 20;
}
if (mDisplayChildren)
{
// Determine total height
U32 child_height = 0;
for (child_list_const_iter_t child_iter = getChildList()->begin();
child_iter != getChildList()->end(); ++child_iter)
{
LLView *childp = *child_iter;
LLRect child_rect = childp->getRequiredRect();
child_height += child_rect.getHeight();
child_height += 2;
}
total_height += child_height;
}
req_rect.mTop = total_height;
return req_rect;
}
void LLContainerView::setLabel(const std::string& label)
{
mLabel = utf8str_to_wstring(label);
}
void LLContainerView::setDisplayChildren(bool displayChildren)
{
mDisplayChildren = displayChildren;
for (child_list_const_iter_t child_iter = getChildList()->begin();
child_iter != getChildList()->end(); ++child_iter)
{
LLView *childp = *child_iter;
childp->setVisible(mDisplayChildren);
}
}
+106
View File
@@ -0,0 +1,106 @@
/**
* @file llcontainerview.h
* @brief Container for all statistics info.
*
* $LicenseInfo:firstyear=2001&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_LLCONTAINERVIEW_H
#define LL_LLCONTAINERVIEW_H
#include "stdtypes.h"
#include "lltextbox.h"
#include "llstatbar.h"
#include "llview.h"
class LLScrollContainer;
struct ContainerViewRegistry : public LLChildRegistry<ContainerViewRegistry>
{
LLSINGLETON_EMPTY_CTOR(ContainerViewRegistry);
};
class LLContainerView : public LLView
{
public:
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
Optional<std::string> label;
Optional<bool> show_label;
Optional<bool> display_children;
// <FS:Zi> Add background visible flag and color to container_view so we can have blank scrollview containers
Optional<bool> background_visible;
Optional<LLUIColor> bg_color;
// </FS:Zi>
Params()
: label("label"),
show_label("show_label", false),
// <FS:Zi> Add background visible flag and color to container_view so we can have blank scrollview containers
background_visible("background_visible", true),
bg_color("bg_color", LLColor4(0.f, 0.f, 0.f, 0.25f)),
// </FS:Zi>
display_children("display_children", true)
{
changeDefault(mouse_opaque, false);
}
};
// my valid children are stored in this registry
typedef ContainerViewRegistry child_registry_t;
protected:
LLContainerView(const Params& p);
friend class LLUICtrlFactory;
public:
~LLContainerView();
/*virtual*/ bool postBuild();
/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
/*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ void draw();
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true);
/*virtual*/ LLRect getRequiredRect(); // Return the height of this object, given the set options.
void setLabel(const std::string& label);
void showLabel(bool show) { mShowLabel = show; }
void setDisplayChildren(bool displayChildren);
bool getDisplayChildren() { return mDisplayChildren; }
void setScrollContainer(LLScrollContainer* scroll) {mScrollContainer = scroll;}
private:
LLScrollContainer* mScrollContainer;
void arrange(S32 width, S32 height, bool called_from_parent = true);
bool mShowLabel;
protected:
bool mDisplayChildren;
LLWString mLabel;
// <FS:Zi> Add background visible flag and color to container_view so we can have blank scrollview containers
bool mBackgroundVisible;
LLUIColor mBackgroundColor;
// </FS:Zi>
};
#endif // LL_CONTAINERVIEW_
+63
View File
@@ -0,0 +1,63 @@
/**
* @file llctrlselectioninterface.cpp
* @brief Programmatic selection of items in a list.
*
* $LicenseInfo:firstyear=2006&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$
*/
#include "linden_common.h"
#include "llctrlselectioninterface.h"
#include "llsd.h"
// virtual
LLCtrlSelectionInterface::~LLCtrlSelectionInterface()
{ }
bool LLCtrlSelectionInterface::selectByValue(LLSD value)
{
return setSelectedByValue(value, true);
}
bool LLCtrlSelectionInterface::deselectByValue(LLSD value)
{
return setSelectedByValue(value, false);
}
// virtual
LLCtrlListInterface::~LLCtrlListInterface()
{ }
LLScrollListItem* LLCtrlListInterface::addSimpleElement(const std::string& value)
{
return addSimpleElement(value, ADD_BOTTOM, LLSD());
}
LLScrollListItem* LLCtrlListInterface::addSimpleElement(const std::string& value, EAddPosition pos)
{
return addSimpleElement(value, pos, LLSD());
}
// virtual
LLCtrlScrollInterface::~LLCtrlScrollInterface()
{ }
+104
View File
@@ -0,0 +1,104 @@
/**
* @file llctrlselectioninterface.h
* @brief Programmatic selection of items in a list.
*
* $LicenseInfo:firstyear=2006&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 LLCTRLSELECTIONINTERFACE_H
#define LLCTRLSELECTIONINTERFACE_H
#include "stdtypes.h"
#include "llstring.h"
#include "llui.h"
class LLSD;
class LLUUID;
class LLScrollListItem;
class LLCtrlSelectionInterface
{
public:
virtual ~LLCtrlSelectionInterface();
enum EOperation
{
OP_DELETE = 1,
OP_SELECT,
OP_DESELECT,
};
virtual bool getCanSelect() const = 0;
virtual S32 getItemCount() const = 0;
virtual bool selectFirstItem() = 0;
virtual bool selectNthItem( S32 index ) = 0;
virtual bool selectItemRange( S32 first, S32 last ) = 0;
virtual S32 getFirstSelectedIndex() const = 0;
// TomY TODO: Simply cast the UUIDs to LLSDs, using the selectByValue function
virtual bool setCurrentByID( const LLUUID& id ) = 0;
virtual LLUUID getCurrentID() const = 0;
bool selectByValue(const LLSD value);
bool deselectByValue(const LLSD value);
virtual bool setSelectedByValue(const LLSD& value, bool selected) = 0;
virtual LLSD getSelectedValue() = 0;
virtual bool isSelected(const LLSD& value) const = 0;
virtual bool operateOnSelection(EOperation op) = 0;
virtual bool operateOnAll(EOperation op) = 0;
};
class LLCtrlListInterface : public LLCtrlSelectionInterface
{
public:
virtual ~LLCtrlListInterface();
virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0;
virtual void clearColumns() = 0;
virtual void setColumnLabel(const std::string& column, const std::string& label) = 0;
// TomY TODO: Document this
virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) = 0;
LLScrollListItem* addSimpleElement(const std::string& value); // defaults to bottom
LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos); // defaults to no LLSD() id
virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos, const LLSD& id) = 0;
virtual void clearRows() = 0;
virtual void sortByColumn(const std::string& name, bool ascending) = 0;
};
class LLCtrlScrollInterface
{
public:
virtual ~LLCtrlScrollInterface();
virtual S32 getScrollPos() const = 0;
virtual void setScrollPos( S32 pos ) = 0;
virtual void scrollToShowSelected() = 0;
};
#endif
+263
View File
@@ -0,0 +1,263 @@
/**
* @file lldockablefloater.cpp
* @brief Creates a panel of a specific kind for a toast
*
* $LicenseInfo:firstyear=2000&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$
*/
#include "linden_common.h"
#include "lldockablefloater.h"
#include "llfloaterreg.h"
//static
LLHandle<LLFloater> LLDockableFloater::sInstanceHandle;
//static
void LLDockableFloater::init(LLDockableFloater* thiz)
{
thiz->setDocked(thiz->mDockControl.get() != NULL
&& thiz->mDockControl.get()->isDockVisible());
thiz->resetInstance();
// all dockable floaters should have close, dock and minimize buttons
thiz->setCanClose(true);
thiz->setCanDock(true);
thiz->setCanMinimize(true);
thiz->setOverlapsScreenChannel(false);
thiz->mForceDocking = false;
}
LLDockableFloater::LLDockableFloater(LLDockControl* dockControl,
const LLSD& key, const Params& params) :
LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(true)
{
init(this);
mUseTongue = true;
}
LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking,
const LLSD& key, const Params& params) :
LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(uniqueDocking)
{
init(this);
mUseTongue = true;
}
LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking,
bool useTongue, const LLSD& key, const Params& params) :
LLFloater(key, params), mDockControl(dockControl), mUseTongue(useTongue), mUniqueDocking(uniqueDocking)
{
init(this);
}
LLDockableFloater::~LLDockableFloater()
{
}
bool LLDockableFloater::postBuild()
{
// Remember we should force docking when the floater is opened for the first time
if (mIsDockedStateForcedCallback != NULL && mIsDockedStateForcedCallback())
{
mForceDocking = true;
}
mDockTongue = LLUI::getUIImage("Flyout_Pointer");
LLFloater::setDocked(true);
return LLView::postBuild();
}
//static
void LLDockableFloater::toggleInstance(const LLSD& sdname)
{
LLSD key;
std::string name = sdname.asString();
LLDockableFloater* instance =
dynamic_cast<LLDockableFloater*> (LLFloaterReg::findInstance(name));
// if floater closed or docked
if (instance == NULL || (instance && instance->isDocked()))
{
LLFloaterReg::toggleInstance(name, key);
// restore button toggle state
if (instance != NULL)
{
instance->storeVisibilityControl();
}
}
// if floater undocked
else if (instance != NULL)
{
instance->setMinimized(false);
if (instance->getVisible())
{
instance->setVisible(false);
}
else
{
instance->setVisible(true);
gFloaterView->bringToFront(instance);
}
}
}
void LLDockableFloater::resetInstance()
{
if (mUniqueDocking && sInstanceHandle.get() != this)
{
if (sInstanceHandle.get() != NULL && sInstanceHandle.get()->isDocked())
{
sInstanceHandle.get()->setVisible(false);
}
sInstanceHandle = getHandle();
}
}
void LLDockableFloater::setVisible(bool visible)
{
// Force docking if requested
if (visible && mForceDocking)
{
setCanDock(true);
setDocked(true);
mForceDocking = false;
}
if(visible && isDocked())
{
resetInstance();
}
if (visible && mDockControl.get() != NULL)
{
mDockControl.get()->repositionDockable();
}
if (visible && !isMinimized())
{
LLFloater::setFrontmost(getAutoFocus());
}
LLFloater::setVisible(visible);
}
void LLDockableFloater::setMinimized(bool minimize)
{
if(minimize && isDocked())
{
// minimizing a docked floater just hides it
setVisible(false);
}
else
{
LLFloater::setMinimized(minimize);
}
}
LLView * LLDockableFloater::getDockWidget()
{
LLView * res = NULL;
if (getDockControl() != NULL) {
res = getDockControl()->getDock();
}
return res;
}
void LLDockableFloater::onDockHidden()
{
setCanDock(false);
}
void LLDockableFloater::onDockShown()
{
if (!isMinimized())
{
setCanDock(true);
}
}
void LLDockableFloater::setDocked(bool docked, bool pop_on_undock)
{
if (mDockControl.get() != NULL && mDockControl.get()->isDockVisible())
{
if (docked)
{
resetInstance();
mDockControl.get()->on();
}
else
{
mDockControl.get()->off();
}
if (!docked && pop_on_undock)
{
// visually pop up a little bit to emphasize the undocking
translate(0, UNDOCK_LEAP_HEIGHT);
}
}
LLFloater::setDocked(docked, pop_on_undock);
}
void LLDockableFloater::draw()
{
if (mDockControl.get() != NULL)
{
mDockControl.get()->repositionDockable();
if (isDocked())
{
mDockControl.get()->drawToungue();
}
}
LLFloater::draw();
}
void LLDockableFloater::setDockControl(LLDockControl* dockControl)
{
mDockControl.reset(dockControl);
setDocked(isDocked());
}
const LLUIImagePtr& LLDockableFloater::getDockTongue(LLDockControl::DocAt dock_side)
{
switch(dock_side)
{
case LLDockControl::LEFT:
mDockTongue = LLUI::getUIImage("Flyout_Left");
break;
case LLDockControl::RIGHT:
mDockTongue = LLUI::getUIImage("Flyout_Right");
break;
default:
mDockTongue = LLUI::getUIImage("Flyout_Pointer");
break;
}
return mDockTongue;
}
LLDockControl* LLDockableFloater::getDockControl()
{
return mDockControl.get();
}
+153
View File
@@ -0,0 +1,153 @@
/**
* @file lldockablefloater.h
* @brief Creates a panel of a specific kind for a toast.
*
* $LicenseInfo:firstyear=2003&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_DOCKABLEFLOATER_H
#define LL_DOCKABLEFLOATER_H
#include "llerror.h"
#include "llfloater.h"
#include "lldockcontrol.h"
#include <memory>
/**
* Represents floater that can dock.
* In case impossibility deriving from LLDockableFloater use LLDockControl.
*/
class LLDockableFloater : public LLFloater
{
static const U32 UNDOCK_LEAP_HEIGHT = 12;
static void init(LLDockableFloater* thiz);
public:
LOG_CLASS(LLDockableFloater);
LLDockableFloater(LLDockControl* dockControl, const LLSD& key,
const Params& params = getDefaultParams());
/**
* Constructor.
* @param dockControl a pointer to the doc control instance
* @param uniqueDocking - a flag defines is docking should work as tab(at one
* moment only one docked floater can be shown), also this flag defines is dock
* tongue should be used.
* @params key a floater key.
* @params params a floater parameters
*/
LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking,
const LLSD& key, const Params& params = getDefaultParams());
/**
* Constructor.
* @param dockControl a pointer to the doc control instance
* @param uniqueDocking - a flag defines is docking should work as tab(at one
* moment only one docked floater can be shown).
* @praram useTongue - a flag defines is dock tongue should be used.
* @params key a floater key.
* @params params a floater parameters
*/
LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking,
bool useTongue, const LLSD& key,
const Params& params = getDefaultParams());
virtual ~LLDockableFloater();
static LLHandle<LLFloater> getInstanceHandle() { return sInstanceHandle; }
static void toggleInstance(const LLSD& sdname);
/**
* If descendant class overrides postBuild() in order to perform specific
* construction then it must still invoke its superclass' implementation.
*/
/* virtula */bool postBuild();
/* virtual */void setDocked(bool docked, bool pop_on_undock = true);
/* virtual */void draw();
/**
* If descendant class overrides setVisible() then it must still invoke its
* superclass' implementation.
*/
/*virtual*/ void setVisible(bool visible);
/**
* If descendant class overrides setMinimized() then it must still invoke its
* superclass' implementation.
*/
/*virtual*/ void setMinimized(bool minimize);
LLView * getDockWidget();
virtual void onDockHidden();
virtual void onDockShown();
LLDockControl* getDockControl();
/**
* Returns true if screen channel should consider floater's size when drawing toasts.
*
* By default returns false.
*/
virtual bool overlapsScreenChannel() const { return mOverlapsScreenChannel && getVisible() && isDocked(); }
virtual void setOverlapsScreenChannel(bool overlaps) { mOverlapsScreenChannel = overlaps; }
bool getUniqueDocking() { return mUniqueDocking; }
bool getUseTongue() { return mUseTongue; }
void setUseTongue(bool use_tongue) { mUseTongue = use_tongue;}
private:
/**
* Provides unique of dockable floater.
* If dockable floater already exists it should be closed.
*/
void resetInstance();
protected:
void setDockControl(LLDockControl* dockControl);
const LLUIImagePtr& getDockTongue(LLDockControl::DocAt dock_side = LLDockControl::TOP);
// Checks if docking should be forced.
// It may be useful e.g. if floater created in mouselook mode (see EXT-5609)
boost::function<bool ()> mIsDockedStateForcedCallback;
//private: // <FS:Ansariel> Make mDockControl accessible from children because of FIRE-16803
std::unique_ptr<LLDockControl> mDockControl;
private: // <FS:Ansariel> Make mDockControl accessible from children because of FIRE-16803
LLUIImagePtr mDockTongue;
static LLHandle<LLFloater> sInstanceHandle;
/**
* Provides possibility to define that dockable floaters can be docked
* non exclusively.
*/
bool mUniqueDocking;
bool mUseTongue;
bool mOverlapsScreenChannel;
// Force docking when the floater is being shown for the first time.
bool mForceDocking;
};
#endif /* LL_DOCKABLEFLOATER_H */
+388
View File
@@ -0,0 +1,388 @@
/**
* @file lldockcontrol.cpp
* @brief Creates a panel of a specific kind for a toast
*
* $LicenseInfo:firstyear=2000&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$
*/
#include "linden_common.h"
#include "lldockcontrol.h"
#include "lldockablefloater.h"
LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) :
mDockableFloater(dockableFloater),
mDockTongue(dockTongue),
mDockTongueX(0),
mDockTongueY(0)
{
mDockAt = dockAt;
if (dockWidget != NULL)
{
mDockWidgetHandle = dockWidget->getHandle();
}
mNonToolbarPanelHandle = mDockableFloater->getRootView()->getChild<LLView>("non_toolbar_panel")->getHandle();
if (dockableFloater->isDocked())
{
on();
}
else
{
off();
}
if (!(get_allowed_rect_callback))
{
mGetAllowedRectCallback = boost::bind(&LLDockControl::getAllowedRect, this, _1);
}
else
{
mGetAllowedRectCallback = get_allowed_rect_callback;
}
if (dockWidget != NULL)
{
repositionDockable();
}
if (getDock() != NULL)
{
mDockWidgetVisible = isDockVisible();
}
else
{
mDockWidgetVisible = false;
}
}
LLDockControl::~LLDockControl()
{
}
void LLDockControl::setDock(LLView* dockWidget)
{
if (dockWidget != NULL)
{
mDockWidgetHandle = dockWidget->getHandle();
repositionDockable();
mDockWidgetVisible = isDockVisible();
}
else
{
mDockWidgetHandle = LLHandle<LLView>();
mDockWidgetVisible = false;
}
}
void LLDockControl::getAllowedRect(LLRect& rect)
{
if(!mNonToolbarPanelHandle.isDead())
{
rect = mNonToolbarPanelHandle.get()->getRect();
}
}
void LLDockControl::repositionDockable()
{
if (!getDock()) return;
LLRect dockRect = getDock()->calcScreenRect();
LLRect rootRect;
LLRect floater_rect = mDockableFloater->calcScreenRect();
mGetAllowedRectCallback(rootRect);
// recalculate dockable position if:
if (mPrevDockRect != dockRect //dock position changed
|| mDockWidgetVisible != isDockVisible() //dock visibility changed
|| mRootRect != rootRect //root view rect changed
|| mFloaterRect != floater_rect //floater rect changed
|| mRecalculateDockablePosition //recalculation is forced
)
{
// undock dockable and off() if dock not visible
if (!isDockVisible())
{
mDockableFloater->setDocked(false);
// force off() since dockable may not have dockControll at this time
off();
LLDockableFloater* dockable_floater =
dynamic_cast<LLDockableFloater*> (mDockableFloater);
if(dockable_floater != NULL)
{
dockable_floater->onDockHidden();
}
}
else
{
if(mEnabled)
{
moveDockable();
}
LLDockableFloater* dockable_floater =
dynamic_cast<LLDockableFloater*> (mDockableFloater);
if(dockable_floater != NULL)
{
dockable_floater->onDockShown();
}
}
mPrevDockRect = dockRect;
mRootRect = rootRect;
mFloaterRect = floater_rect;
mRecalculateDockablePosition = false;
mDockWidgetVisible = isDockVisible();
}
}
bool LLDockControl::isDockVisible()
{
bool res = true;
if (getDock() != NULL)
{
//we should check all hierarchy
res = getDock()->isInVisibleChain();
if (res)
{
LLRect dockRect = getDock()->calcScreenRect();
switch (mDockAt)
{
case LEFT: // to keep compiler happy
break;
case BOTTOM:
case TOP:
{
// check is dock inside parent rect
// assume that parent for all dockable floaters
// is the root view
LLRect dockParentRect =
getDock()->getRootView()->calcScreenRect();
if (dockRect.mRight <= dockParentRect.mLeft
|| dockRect.mLeft >= dockParentRect.mRight)
{
res = false;
}
break;
}
default:
break;
}
}
}
return res;
}
void LLDockControl::moveDockable()
{
// calculate new dockable position
LLRect dockRect = getDock()->calcScreenRect();
LLRect rootRect;
mGetAllowedRectCallback(rootRect);
bool use_tongue = false;
LLDockableFloater* dockable_floater =
dynamic_cast<LLDockableFloater*> (mDockableFloater);
if (dockable_floater != NULL)
{
use_tongue = dockable_floater->getUseTongue();
}
LLRect dockableRect = mDockableFloater->calcScreenRect();
S32 x = 0;
S32 y = 0;
LLRect dockParentRect;
switch (mDockAt)
{
case LEFT:
x = dockRect.mLeft - dockableRect.getWidth();
y = dockRect.getCenterY() + dockableRect.getHeight() / 2;
if (use_tongue)
{
x -= mDockTongue->getWidth();
}
mDockTongueX = dockableRect.mRight;
mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2;
break;
case RIGHT:
x = dockRect.mRight;
y = dockRect.getCenterY() + dockableRect.getHeight() / 2;
if (use_tongue)
{
x += mDockTongue->getWidth();
}
mDockTongueX = dockRect.mRight;
mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2;
break;
case TOP:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
y = dockRect.mTop + dockableRect.getHeight();
// unique docking used with dock tongue, so add tongue height to the Y coordinate
if (use_tongue)
{
y += mDockTongue->getHeight();
if ( y > rootRect.mTop)
{
y = rootRect.mTop;
}
}
// check is dockable inside root view rect
if (x < rootRect.mLeft)
{
x = rootRect.mLeft;
}
if (x + dockableRect.getWidth() > rootRect.mRight)
{
x = rootRect.mRight - dockableRect.getWidth();
}
// calculate dock tongue position
dockParentRect = getDock()->getParent()->calcScreenRect();
if (dockRect.getCenterX() < dockParentRect.mLeft)
{
mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2;
}
else if (dockRect.getCenterX() > dockParentRect.mRight)
{
mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;;
}
else
{
mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2;
}
mDockTongueY = dockRect.mTop;
break;
case BOTTOM:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
y = dockRect.mBottom;
// unique docking used with dock tongue, so add tongue height to the Y coordinate
if (use_tongue)
{
y -= mDockTongue->getHeight();
}
// check is dockable inside root view rect
if (x < rootRect.mLeft)
{
x = rootRect.mLeft;
}
if (x + dockableRect.getWidth() > rootRect.mRight)
{
x = rootRect.mRight - dockableRect.getWidth();
}
// calculate dock tongue position
dockParentRect = getDock()->getParent()->calcScreenRect();
if (dockRect.getCenterX() < dockParentRect.mLeft)
{
mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2;
}
else if (dockRect.getCenterX() > dockParentRect.mRight)
{
mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;;
}
else
{
mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2;
}
mDockTongueY = dockRect.mBottom - mDockTongue->getHeight();
break;
}
S32 max_available_height = rootRect.getHeight() - (rootRect.mBottom - mDockTongueY) - mDockTongue->getHeight();
// A floater should be shrunk so it doesn't cover a part of its docking tongue and
// there is a space between a dockable floater and a control to which it is docked.
if (use_tongue && dockableRect.getHeight() >= max_available_height)
{
dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), max_available_height);
mDockableFloater->reshape(dockableRect.getWidth(), dockableRect.getHeight());
}
else
{
// move dockable
dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
dockableRect.getHeight());
}
LLRect localDocableParentRect;
mDockableFloater->getParent()->screenRectToLocal(dockableRect, &localDocableParentRect);
mDockableFloater->setRect(localDocableParentRect);
mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, &mDockTongueX, &mDockTongueY);
}
void LLDockControl::on()
{
if (isDockVisible())
{
mEnabled = true;
mRecalculateDockablePosition = true;
}
}
void LLDockControl::off()
{
mEnabled = false;
}
void LLDockControl::forceRecalculatePosition()
{
mRecalculateDockablePosition = true;
}
void LLDockControl::drawToungue()
{
bool use_tongue = false;
LLDockableFloater* dockable_floater =
dynamic_cast<LLDockableFloater*> (mDockableFloater);
if (dockable_floater != NULL)
{
use_tongue = dockable_floater->getUseTongue();
}
if (mEnabled && use_tongue)
{
mDockTongue->draw(mDockTongueX, mDockTongueY);
}
}
+97
View File
@@ -0,0 +1,97 @@
/**
* @file lldockcontrol.h
* @brief Creates a panel of a specific kind for a toast.
*
* $LicenseInfo:firstyear=2003&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_DOCKCONTROL_H
#define LL_DOCKCONTROL_H
#include "llerror.h"
#include "llview.h"
#include "llfloater.h"
#include "lluiimage.h"
/**
* Provides services for docking of specified floater.
* This class should be used in case impossibility deriving from LLDockableFloater.
*/
class LLDockControl
{
public:
enum DocAt
{
TOP,
LEFT,
RIGHT,
BOTTOM
};
public:
// callback for a function getting a rect valid for control's position
typedef boost::function<void (LLRect& )> get_allowed_rect_callback_t;
LOG_CLASS(LLDockControl);
LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_rect_callback = NULL);
virtual ~LLDockControl();
public:
void on();
void off();
void forceRecalculatePosition();
void setDock(LLView* dockWidget);
LLView* getDock()
{
return mDockWidgetHandle.get();
}
void repositionDockable();
void drawToungue();
bool isDockVisible();
// gets a rect that bounds possible positions for a dockable control (EXT-1111)
void getAllowedRect(LLRect& rect);
S32 getTongueWidth() { return mDockTongue->getWidth(); }
S32 getTongueHeight() { return mDockTongue->getHeight(); }
private:
virtual void moveDockable();
private:
get_allowed_rect_callback_t mGetAllowedRectCallback;
bool mEnabled;
bool mRecalculateDockablePosition;
bool mDockWidgetVisible;
DocAt mDockAt;
LLHandle<LLView> mDockWidgetHandle;
LLHandle<LLView> mNonToolbarPanelHandle;
LLRect mPrevDockRect;
LLRect mRootRect;
LLRect mFloaterRect;
LLFloater* mDockableFloater;
LLUIImagePtr mDockTongue;
S32 mDockTongueX;
S32 mDockTongueY;
};
#endif /* LL_DOCKCONTROL_H */
+396
View File
@@ -0,0 +1,396 @@
/**
* @file lldraghandle.cpp
* @brief LLDragHandle base class
*
* $LicenseInfo:firstyear=2001&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$
*/
// A widget for dragging a view around the screen using the mouse.
#include "linden_common.h"
#include "lldraghandle.h"
#include "llmath.h"
//#include "llviewerwindow.h"
#include "llui.h"
#include "llmenugl.h"
#include "lltextbox.h"
#include "llcontrol.h"
#include "llfontgl.h"
#include "llwindow.h"
#include "llfocusmgr.h"
#include "lluictrlfactory.h"
const S32 LEADING_PAD = 5;
const S32 TITLE_HPAD = 8;
const S32 BORDER_PAD = 1;
const S32 LEFT_PAD = BORDER_PAD + TITLE_HPAD + LEADING_PAD;
S32 LLDragHandle::sSnapMargin = 5;
LLDragHandle::LLDragHandle(const LLDragHandle::Params& p)
: LLView(p),
mLabelVPadding(p.label_v_padding), // <FS:Zi> Make vertical label padding a per-skin option
mDragLastScreenX( 0 ),
mDragLastScreenY( 0 ),
mLastMouseScreenX( 0 ),
mLastMouseScreenY( 0 ),
mTitleBox( NULL ),
mMaxTitleWidth( 0 ),
mForeground( true ),
mDragHighlightColor(p.drag_highlight_color()),
mDragShadowColor(p.drag_shadow_color())
{
static LLUICachedControl<S32> snap_margin ("SnapMargin", 0);
sSnapMargin = snap_margin;
}
LLDragHandle::~LLDragHandle()
{
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
removeChild(mTitleBox);
delete mTitleBox;
}
void LLDragHandle::initFromParams(const LLDragHandle::Params& p)
{
LLView::initFromParams(p);
setTitle( p.label );
}
void LLDragHandle::setTitleVisible(bool visible)
{
if(mTitleBox)
{
mTitleBox->setVisible(visible);
}
}
void LLDragHandleTop::setTitle(const std::string& title)
{
std::string trimmed_title = title;
LLStringUtil::trim(trimmed_title);
if( mTitleBox )
{
mTitleBox->setText(trimmed_title);
}
else
{
const LLFontGL* font = LLFontGL::getFontSansSerif();
LLTextBox::Params params;
params.name("Drag Handle Title");
params.rect(getRect());
params.initial_value(trimmed_title);
params.font(font);
params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT);
params.font_shadow(LLFontGL::DROP_SHADOW_SOFT);
params.use_ellipses = true;
params.parse_urls = false; //cancel URL replacement in floater title
mTitleBox = LLUICtrlFactory::create<LLTextBox> (params);
addChild( mTitleBox );
}
reshapeTitleBox();
}
std::string LLDragHandleTop::getTitle() const
{
return mTitleBox == NULL ? LLStringUtil::null : mTitleBox->getText();
}
void LLDragHandleLeft::setTitle(const std::string& )
{
if( mTitleBox )
{
removeChild(mTitleBox);
delete mTitleBox;
mTitleBox = NULL;
}
/* no title on left edge */
}
std::string LLDragHandleLeft::getTitle() const
{
return LLStringUtil::null;
}
void LLDragHandleTop::draw()
{
/* Disable lines. Can drag anywhere in most windows. JC
if( getVisible() && getEnabled() && mForeground)
{
const S32 BORDER_PAD = 2;
const S32 HPAD = 2;
const S32 VPAD = 2;
S32 left = BORDER_PAD + HPAD;
S32 top = getRect().getHeight() - 2 * VPAD;
S32 right = getRect().getWidth() - HPAD;
// S32 bottom = VPAD;
// draw lines for drag areas
const S32 LINE_SPACING = (DRAG_HANDLE_HEIGHT - 2 * VPAD) / 4;
S32 line = top - LINE_SPACING;
LLRect title_rect = mTitleBox->getRect();
S32 title_right = title_rect.mLeft + mTitleWidth;
bool show_right_side = title_right < getRect().getWidth();
for( S32 i=0; i<4; i++ )
{
gl_line_2d(left, line+1, title_rect.mLeft - LEADING_PAD, line+1, mDragHighlightColor);
if( show_right_side )
{
gl_line_2d(title_right, line+1, right, line+1, mDragHighlightColor);
}
gl_line_2d(left, line, title_rect.mLeft - LEADING_PAD, line, mDragShadowColor);
if( show_right_side )
{
gl_line_2d(title_right, line, right, line, mDragShadowColor);
}
line -= LINE_SPACING;
}
}
*/
// Colorize the text to match the frontmost state
if (mTitleBox)
{
mTitleBox->setEnabled(getForeground());
}
LLView::draw();
}
// assumes GL state is set for 2D
void LLDragHandleLeft::draw()
{
/* Disable lines. Can drag anywhere in most windows. JC
if( getVisible() && getEnabled() && mForeground )
{
const S32 BORDER_PAD = 2;
// const S32 HPAD = 2;
const S32 VPAD = 2;
const S32 LINE_SPACING = 3;
S32 left = BORDER_PAD + LINE_SPACING;
S32 top = getRect().getHeight() - 2 * VPAD;
// S32 right = getRect().getWidth() - HPAD;
S32 bottom = VPAD;
// draw lines for drag areas
// no titles yet
//LLRect title_rect = mTitleBox->getRect();
//S32 title_right = title_rect.mLeft + mTitleWidth;
//bool show_right_side = title_right < getRect().getWidth();
S32 line = left;
for( S32 i=0; i<4; i++ )
{
gl_line_2d(line, top, line, bottom, mDragHighlightColor);
gl_line_2d(line+1, top, line+1, bottom, mDragShadowColor);
line += LINE_SPACING;
}
}
*/
// Colorize the text to match the frontmost state
if (mTitleBox)
{
mTitleBox->setEnabled(getForeground());
}
LLView::draw();
}
void LLDragHandleTop::reshapeTitleBox()
{
// <FS:Zi> Make vertical label padding a per-skin option
// static LLUICachedControl<S32> title_vpad("UIFloaterTitleVPad", 0);
static LLUICachedControl<S32> default_title_vpad("UIFloaterTitleVPad", 0);
S32 title_vpad=mLabelVPadding;
if(title_vpad==-1)
{
title_vpad=default_title_vpad;
}
// </FS:Zi>
if( ! mTitleBox)
{
return;
}
const LLFontGL* font = LLFontGL::getFontSansSerif();
S32 title_width = getRect().getWidth();
title_width -= LEFT_PAD + 2 * BORDER_PAD + getButtonsRect().getWidth();
S32 title_height = font->getLineHeight();
LLRect title_rect;
title_rect.setLeftTopAndSize(
LEFT_PAD,
getRect().getHeight() - title_vpad,
title_width,
title_height);
// calls reshape on mTitleBox
mTitleBox->setShape( title_rect );
}
void LLDragHandleTop::reshape(S32 width, S32 height, bool called_from_parent)
{
LLView::reshape(width, height, called_from_parent);
reshapeTitleBox();
}
void LLDragHandleLeft::reshape(S32 width, S32 height, bool called_from_parent)
{
LLView::reshape(width, height, called_from_parent);
}
//-------------------------------------------------------------
// UI event handling
//-------------------------------------------------------------
bool LLDragHandle::handleMouseDown(S32 x, S32 y, MASK mask)
{
// Route future Mouse messages here preemptively. (Release on mouse up.)
// No handler needed for focus lost since this clas has no state that depends on it.
gFocusMgr.setMouseCapture(this);
localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY);
mLastMouseScreenX = mDragLastScreenX;
mLastMouseScreenY = mDragLastScreenY;
// Note: don't pass on to children
return true;
}
bool LLDragHandle::handleMouseUp(S32 x, S32 y, MASK mask)
{
if( hasMouseCapture() )
{
// Release the mouse
gFocusMgr.setMouseCapture( NULL );
}
// Note: don't pass on to children
return true;
}
bool LLDragHandle::handleHover(S32 x, S32 y, MASK mask)
{
bool handled = false;
// We only handle the click if the click both started and ended within us
if( hasMouseCapture() )
{
S32 screen_x;
S32 screen_y;
localPointToScreen(x, y, &screen_x, &screen_y);
// Resize the parent
S32 delta_x = screen_x - mDragLastScreenX;
S32 delta_y = screen_y - mDragLastScreenY;
// if dragging a docked floater we want to undock
LLFloater * parent = dynamic_cast<LLFloater *>(getParent());
if (parent && parent->isDocked())
{
const S32 SLOP = 12;
if (delta_y <= -SLOP ||
delta_y >= SLOP)
{
parent->setDocked(false, false);
return true;
}
else
{
return false;
}
}
LLRect original_rect = getParent()->getRect();
LLRect translated_rect = getParent()->getRect();
translated_rect.translate(delta_x, delta_y);
// temporarily slam dragged window to new position
getParent()->setRect(translated_rect);
S32 pre_snap_x = getParent()->getRect().mLeft;
S32 pre_snap_y = getParent()->getRect().mBottom;
mDragLastScreenX = screen_x;
mDragLastScreenY = screen_y;
LLRect new_rect;
LLCoordGL mouse_dir;
// use hysteresis on mouse motion to preserve user intent when mouse stops moving
mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX;
mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY;
mLastMouseDir = mouse_dir;
mLastMouseScreenX = screen_x;
mLastMouseScreenY = screen_y;
LLView* snap_view = getParent()->findSnapRect(new_rect, mouse_dir, SNAP_PARENT_AND_SIBLINGS, sSnapMargin);
getParent()->setSnappedTo(snap_view);
delta_x = new_rect.mLeft - pre_snap_x;
delta_y = new_rect.mBottom - pre_snap_y;
translated_rect.translate(delta_x, delta_y);
// restore original rect so delta are detected, then call user reshape method to handle snapped floaters, etc
getParent()->setRect(original_rect);
getParent()->setShape(translated_rect, true);
mDragLastScreenX += delta_x;
mDragLastScreenY += delta_y;
getWindow()->setCursor(UI_CURSOR_ARROW);
LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" <<LL_ENDL;
handled = true;
}
else
{
getWindow()->setCursor(UI_CURSOR_ARROW);
LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL;
handled = true;
}
// Note: don't pass on to children
return handled;
}
void LLDragHandle::setValue(const LLSD& value)
{
setTitle(value.asString());
}
+144
View File
@@ -0,0 +1,144 @@
/**
* @file lldraghandle.h
* @brief LLDragHandle base class
*
* $LicenseInfo:firstyear=2001&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$
*/
// A widget for dragging a view around the screen using the mouse.
#ifndef LL_DRAGHANDLE_H
#define LL_DRAGHANDLE_H
#include "llview.h"
#include "v4color.h"
#include "llrect.h"
#include "llcoord.h"
class LLTextBox;
class LLDragHandle : public LLView
{
public:
struct Params
: public LLInitParam::Block<Params, LLView::Params>
{
Optional<std::string> label;
Optional<LLUIColor> drag_highlight_color;
Optional<LLUIColor> drag_shadow_color;
Optional<S32> label_v_padding; // <FS:Zi> Make vertical label padding a per-skin option
Params()
: label("label"),
label_v_padding("label_v_padding", -1), // <FS:Zi> Make vertical label padding a per-skin option
drag_highlight_color("drag_highlight_color", LLUIColorTable::instance().getColor("DefaultHighlightLight")),
drag_shadow_color("drag_shadow_color", LLUIColorTable::instance().getColor("DefaultShadowDark"))
{
changeDefault(mouse_opaque, true);
changeDefault(follows.flags, FOLLOWS_ALL);
}
};
void initFromParams(const Params&);
virtual ~LLDragHandle();
virtual void setValue(const LLSD& value);
void setForeground(bool b) { mForeground = b; }
bool getForeground() const { return mForeground; }
void setMaxTitleWidth(S32 max_width) {mMaxTitleWidth = llmin(max_width, mMaxTitleWidth); }
S32 getMaxTitleWidth() const { return mMaxTitleWidth; }
void setButtonsRect(const LLRect& rect){ mButtonsRect = rect; }
LLRect getButtonsRect() { return mButtonsRect; }
void setTitleVisible(bool visible);
virtual void setTitle( const std::string& title ) = 0;
virtual std::string getTitle() const = 0;
virtual bool handleHover(S32 x, S32 y, MASK mask);
virtual bool handleMouseDown(S32 x, S32 y, MASK mask);
virtual bool handleMouseUp(S32 x, S32 y, MASK mask);
protected:
LLDragHandle(const Params&);
friend class LLUICtrlFactory;
protected:
LLTextBox* mTitleBox;
private:
LLRect mButtonsRect;
S32 mDragLastScreenX;
S32 mDragLastScreenY;
S32 mLastMouseScreenX;
S32 mLastMouseScreenY;
LLCoordGL mLastMouseDir;
LLUIColor mDragHighlightColor;
LLUIColor mDragShadowColor;
S32 mMaxTitleWidth;
bool mForeground;
// Pixels near the edge to snap floaters.
static S32 sSnapMargin;
protected:
S32 mLabelVPadding; // <FS:Zi> Make vertical label padding a per-skin option
};
// Use this one for traditional top-of-window draggers
class LLDragHandleTop
: public LLDragHandle
{
protected:
LLDragHandleTop(const Params& p) : LLDragHandle(p) {}
friend class LLUICtrlFactory;
public:
virtual void setTitle( const std::string& title );
virtual std::string getTitle() const;
virtual void draw();
virtual void reshape(S32 width, S32 height, bool called_from_parent = true);
private:
void reshapeTitleBox();
};
// Use this for left-side, vertical text draggers
class LLDragHandleLeft
: public LLDragHandle
{
protected:
LLDragHandleLeft(const Params& p) : LLDragHandle(p) {}
friend class LLUICtrlFactory;
public:
virtual void setTitle( const std::string& title );
virtual std::string getTitle() const;
virtual void draw();
virtual void reshape(S32 width, S32 height, bool called_from_parent = true);
};
const S32 DRAG_HANDLE_HEIGHT = 16;
const S32 DRAG_HANDLE_WIDTH = 16;
#endif // LL_DRAGHANDLE_H
+40
View File
@@ -0,0 +1,40 @@
/**
* @file lleditmenuhandler.cpp
* @authors Aaron Yonas, James Cook
*
* $LicenseInfo:firstyear=2006&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$
*/
#include "linden_common.h"
#include "lleditmenuhandler.h"
/* static */
LLEditMenuHandler* LLEditMenuHandler::gEditMenuHandler = NULL;
LLEditMenuHandler::~LLEditMenuHandler()
{
if (gEditMenuHandler == this)
{
gEditMenuHandler = NULL;
}
}
+71
View File
@@ -0,0 +1,71 @@
/**
* @file lleditmenuhandler.h
* @authors Aaron Yonas, James Cook
*
* $LicenseInfo:firstyear=2006&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 LLEDITMENUHANDLER_H
#define LLEDITMENUHANDLER_H
// Interface used by menu system for plug-in hotkey/menu handling
class LLEditMenuHandler
{
public:
// this is needed even though this is just an interface class.
virtual ~LLEditMenuHandler();
virtual void undo() {};
virtual bool canUndo() const { return false; }
virtual void redo() {};
virtual bool canRedo() const { return false; }
virtual void cut() {};
virtual bool canCut() const { return false; }
virtual void copy() {};
virtual bool canCopy() const { return false; }
virtual void paste() {};
virtual bool canPaste() const { return false; }
// "delete" is a keyword
virtual void doDelete() {};
virtual bool canDoDelete() const { return false; }
virtual void selectAll() {};
virtual bool canSelectAll() const { return false; }
virtual void deselect() {};
virtual bool canDeselect() const { return false; }
// TODO: Instead of being a public data member, it would be better to hide it altogether
// and have a "set" method and then a bunch of static versions of the cut, copy, paste
// methods, etc that operate on the current global instance. That would drastically
// simplify the existing code that accesses this global variable by putting all the
// null checks in the one implementation of those static methods. -MG
static LLEditMenuHandler* gEditMenuHandler;
};
#endif
+469
View File
@@ -0,0 +1,469 @@
/**
* @file llemojidictionary.cpp
* @brief Implementation of LLEmojiDictionary
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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$
*/
#include "linden_common.h"
#include "lldir.h"
#include "llemojidictionary.h"
#include "llsdserialize.h"
#include <boost/algorithm/string.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/algorithm/transform.hpp>
// ============================================================================
// Constants
//
static const std::string SKINNED_EMOJI_FILENAME("emoji_characters.xml");
static const std::string SKINNED_CATEGORY_FILENAME("emoji_categories.xml");
static const std::string COMMON_GROUP_FILENAME("emoji_groups.xml");
static const std::string GROUP_NAME_SKIP("skip");
// https://www.compart.com/en/unicode/U+1F302
static const S32 GROUP_OTHERS_IMAGE_INDEX = 0x1F302;
// ============================================================================
// Helper functions
//
template<class T>
std::list<T> llsd_array_to_list(const LLSD& sd, std::function<void(T&)> mutator = {});
template<>
std::list<std::string> llsd_array_to_list(const LLSD& sd, std::function<void(std::string&)> mutator)
{
std::list<std::string> result;
for (LLSD::array_const_iterator it = sd.beginArray(), end = sd.endArray(); it != end; ++it)
{
const LLSD& entry = *it;
if (!entry.isString())
continue;
result.push_back(entry.asStringRef());
if (mutator)
{
mutator(result.back());
}
}
return result;
}
struct emoji_filter_base
{
emoji_filter_base(const std::string& needle)
{
// Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category
mNeedle = (boost::starts_with(needle, ":")) ? needle.substr(1) : needle;
LLStringUtil::toLower(mNeedle);
}
protected:
std::string mNeedle;
};
struct emoji_filter_shortcode_or_category_contains : public emoji_filter_base
{
emoji_filter_shortcode_or_category_contains(const std::string& needle) : emoji_filter_base(needle) {}
bool operator()(const LLEmojiDescriptor& descr) const
{
for (const auto& short_code : descr.ShortCodes)
{
if (boost::icontains(short_code, mNeedle))
return true;
}
if (boost::icontains(descr.Category, mNeedle))
return true;
return false;
}
};
std::string LLEmojiDescriptor::getShortCodes() const
{
std::string result;
for (const std::string& shortCode : ShortCodes)
{
if (!result.empty())
{
result += ", ";
}
result += shortCode;
}
return result;
}
// ============================================================================
// LLEmojiDictionary class
//
LLEmojiDictionary::LLEmojiDictionary()
{
}
// static
void LLEmojiDictionary::initClass()
{
LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton();
pThis->loadTranslations();
pThis->loadGroups();
pThis->loadEmojis();
}
LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const
{
LLWString result;
boost::transform(mEmojis | boost::adaptors::filtered(emoji_filter_shortcode_or_category_contains(needle)),
std::back_inserter(result), [](const auto& descr) { return descr.Character; });
return result;
}
// static
bool LLEmojiDictionary::searchInShortCode(std::size_t& begin, std::size_t& end, const std::string& shortCode, const std::string& needle)
{
begin = 0;
end = 1;
std::size_t index = 1;
// Search for begin
char d = tolower(needle[index++]);
while (end < shortCode.size())
{
char s = tolower(shortCode[end++]);
if (s == d)
{
begin = end - 1;
break;
}
}
if (!begin)
return false;
// Search for end
d = tolower(needle[index++]);
if (!d)
return true;
while (end < shortCode.size() && index <= needle.size())
{
char s = tolower(shortCode[end++]);
if (s == d)
{
if (index == needle.size())
return true;
d = tolower(needle[index++]);
continue;
}
switch (s)
{
case L'-':
case L'_':
case L'+':
continue;
}
break;
}
return false;
}
void LLEmojiDictionary::findByShortCode(
std::vector<LLEmojiSearchResult>& result,
const std::string& needle
) const
{
result.clear();
if (needle.empty() || needle.front() != ':')
return;
std::map<llwchar, std::vector<LLEmojiSearchResult>> results;
for (const LLEmojiDescriptor& d : mEmojis)
{
if (!d.ShortCodes.empty())
{
const std::string& shortCode = d.ShortCodes.front();
if (shortCode.size() >= needle.size() && shortCode.front() == needle.front())
{
std::size_t begin, end;
if (searchInShortCode(begin, end, shortCode, needle))
{
results[static_cast<llwchar>(begin)].emplace_back(d.Character, shortCode, begin, end);
}
}
}
}
for (const auto& it : results)
{
#ifdef __cpp_lib_containers_ranges
result.append_range(it.second);
#else
result.insert(result.end(), it.second.cbegin(), it.second.cend());
#endif
}
}
const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromEmoji(llwchar emoji) const
{
const auto it = mEmoji2Descr.find(emoji);
return (mEmoji2Descr.end() != it) ? it->second : nullptr;
}
const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromShortCode(const std::string& short_code) const
{
const auto it = mShortCode2Descr.find(short_code);
return (mShortCode2Descr.end() != it) ? it->second : nullptr;
}
std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) const
{
const auto it = mEmoji2Descr.find(ch);
return (mEmoji2Descr.end() != it) ? it->second->ShortCodes.front() : LLStringUtil::null;
}
bool LLEmojiDictionary::isEmoji(llwchar ch) const
{
// Currently used codes: A9,AE,203C,2049,2122,...,2B55,3030,303D,3297,3299,1F004,...,1FAF6
if (ch == 0xA9 || ch == 0xAE || (ch >= 0x2000 && ch < 0x3300) || (ch >= 0x1F000 && ch < 0x20000))
{
return mEmoji2Descr.find(ch) != mEmoji2Descr.end();
}
return false;
}
void LLEmojiDictionary::loadTranslations()
{
std::vector<std::string> filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_CATEGORY_FILENAME, LLDir::CURRENT_SKIN);
if (filenames.empty())
{
LL_WARNS() << "Emoji file categories not found" << LL_ENDL;
return;
}
const std::string filename = filenames.back();
llifstream file(filename.c_str());
if (!file.is_open())
{
LL_WARNS() << "Emoji file categories failed to open" << LL_ENDL;
return;
}
LL_DEBUGS() << "Loading emoji categories file at " << filename << LL_ENDL;
LLSD data;
LLSDSerialize::fromXML(data, file);
if (data.isUndefined())
{
LL_WARNS() << "Emoji file categories missing or ill-formed" << LL_ENDL;
return;
}
// Register translations for all categories
for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it)
{
const LLSD& sd = *it;
const std::string& name = sd["Name"].asStringRef();
const std::string& category = sd["Category"].asStringRef();
if (!name.empty() && !category.empty())
{
mTranslations[name] = category;
}
else
{
LL_WARNS() << "Skipping invalid emoji category '" << name << "' => '" << category << "'" << LL_ENDL;
}
}
}
void LLEmojiDictionary::loadGroups()
{
const std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, COMMON_GROUP_FILENAME);
llifstream file(filename.c_str());
if (!file.is_open())
{
LL_WARNS() << "Emoji file groups failed to open" << LL_ENDL;
return;
}
LL_DEBUGS() << "Loading emoji groups file at " << filename << LL_ENDL;
LLSD data;
LLSDSerialize::fromXML(data, file);
if (data.isUndefined())
{
LL_WARNS() << "Emoji file groups missing or ill-formed" << LL_ENDL;
return;
}
mGroups.clear();
// Register all groups
for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it)
{
const LLSD& sd = *it;
const std::string& name = sd["Name"].asStringRef();
if (name == GROUP_NAME_SKIP)
{
mSkipCategories = loadCategories(sd);
translateCategories(mSkipCategories);
}
else
{
// Add new group
mGroups.emplace_back();
LLEmojiGroup& group = mGroups.back();
group.Character = loadIcon(sd);
group.Categories = loadCategories(sd);
translateCategories(group.Categories);
for (const std::string& category : group.Categories)
{
mCategory2Group.insert(std::make_pair(category, &group));
}
}
}
// Add group "others"
mGroups.emplace_back();
mGroups.back().Character = GROUP_OTHERS_IMAGE_INDEX;
}
void LLEmojiDictionary::loadEmojis()
{
std::vector<std::string> filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN);
if (filenames.empty())
{
LL_WARNS() << "Emoji file characters not found" << LL_ENDL;
return;
}
const std::string filename = filenames.back();
llifstream file(filename.c_str());
if (!file.is_open())
{
LL_WARNS() << "Emoji file characters failed to open" << LL_ENDL;
return;
}
LL_DEBUGS() << "Loading emoji characters file at " << filename << LL_ENDL;
LLSD data;
LLSDSerialize::fromXML(data, file);
if (data.isUndefined())
{
LL_WARNS() << "Emoji file characters missing or ill-formed" << LL_ENDL;
return;
}
for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it)
{
const LLSD& sd = *it;
llwchar icon = loadIcon(sd);
if (!icon)
{
LL_WARNS() << "Skipping invalid emoji descriptor (no icon)" << LL_ENDL;
continue;
}
std::list<std::string> categories = loadCategories(sd);
if (categories.empty())
{
LL_WARNS() << "Skipping invalid emoji descriptor (no categories)" << LL_ENDL;
continue;
}
std::string category = categories.front();
if (std::find(mSkipCategories.begin(), mSkipCategories.end(), category) != mSkipCategories.end())
{
// This category is listed for skip
continue;
}
std::list<std::string> shortCodes = loadShortCodes(sd);
if (shortCodes.empty())
{
LL_WARNS() << "Skipping invalid emoji descriptor (no shortCodes)" << LL_ENDL;
continue;
}
if (mCategory2Group.find(category) == mCategory2Group.end())
{
// Add unknown category to "others" group
mGroups.back().Categories.push_back(category);
mCategory2Group.insert(std::make_pair(category, &mGroups.back()));
}
mEmojis.emplace_back();
LLEmojiDescriptor& emoji = mEmojis.back();
emoji.Character = icon;
emoji.Category = category;
emoji.ShortCodes = std::move(shortCodes);
mEmoji2Descr.insert(std::make_pair(icon, &emoji));
mCategory2Descrs[category].push_back(&emoji);
for (const std::string& shortCode : emoji.ShortCodes)
{
mShortCode2Descr.insert(std::make_pair(shortCode, &emoji));
}
}
}
llwchar LLEmojiDictionary::loadIcon(const LLSD& sd)
{
// We don't currently support character composition
const LLWString icon = utf8str_to_wstring(sd["Character"].asString());
return (1 == icon.size()) ? icon[0] : L'\0';
}
std::list<std::string> LLEmojiDictionary::loadCategories(const LLSD& sd)
{
static const std::string key("Categories");
return llsd_array_to_list<std::string>(sd[key]);
}
std::list<std::string> LLEmojiDictionary::loadShortCodes(const LLSD& sd)
{
static const std::string key("ShortCodes");
auto toLower = [](std::string& str) { LLStringUtil::toLower(str); };
return llsd_array_to_list<std::string>(sd[key], toLower);
}
void LLEmojiDictionary::translateCategories(std::list<std::string>& categories)
{
for (std::string& category : categories)
{
auto it = mTranslations.find(category);
if (it != mTranslations.end())
{
category = it->second;
}
}
}
// ============================================================================
+126
View File
@@ -0,0 +1,126 @@
/**
* @file llemojidictionary.h
* @brief Header file for LLEmojiDictionary
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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$
*/
#pragma once
#include "lldictionary.h"
#include "llinitdestroyclass.h"
#include "llsingleton.h"
// ============================================================================
// LLEmojiDescriptor class
//
struct LLEmojiDescriptor
{
llwchar Character;
std::string Category;
std::list<std::string> ShortCodes;
std::string getShortCodes() const;
};
// ============================================================================
// LLEmojiGroup class
//
struct LLEmojiGroup
{
llwchar Character;
std::list<std::string> Categories;
};
// ============================================================================
// LLEmojiSearchResult class
//
struct LLEmojiSearchResult
{
llwchar Character;
std::string String;
std::size_t Begin, End;
LLEmojiSearchResult(llwchar character, const std::string& string, std::size_t begin, std::size_t end)
: Character(character)
, String(string)
, Begin(begin)
, End(end)
{
}
};
// ============================================================================
// LLEmojiDictionary class
//
class LLEmojiDictionary : public LLParamSingleton<LLEmojiDictionary>, public LLInitClass<LLEmojiDictionary>
{
LLSINGLETON(LLEmojiDictionary);
~LLEmojiDictionary() override {};
public:
typedef std::map<std::string, std::string> cat2cat_map_t;
typedef std::map<std::string, const LLEmojiGroup*> cat2group_map_t;
typedef std::map<llwchar, const LLEmojiDescriptor*> emoji2descr_map_t;
typedef std::map<std::string, const LLEmojiDescriptor*> code2descr_map_t;
typedef std::map<std::string, std::vector<const LLEmojiDescriptor*>> cat2descrs_map_t;
static void initClass();
LLWString findMatchingEmojis(const std::string& needle) const;
static bool searchInShortCode(std::size_t& begin, std::size_t& end, const std::string& shortCode, const std::string& needle);
void findByShortCode(std::vector<LLEmojiSearchResult>& result, const std::string& needle) const;
const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const;
const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const;
std::string getNameFromEmoji(llwchar ch) const;
bool isEmoji(llwchar ch) const;
const std::vector<LLEmojiGroup>& getGroups() const { return mGroups; }
const emoji2descr_map_t& getEmoji2Descr() const { return mEmoji2Descr; }
const cat2descrs_map_t& getCategory2Descrs() const { return mCategory2Descrs; }
const code2descr_map_t& getShortCode2Descr() const { return mShortCode2Descr; }
private:
void loadTranslations();
void loadGroups();
void loadEmojis();
static llwchar loadIcon(const LLSD& sd);
static std::list<std::string> loadCategories(const LLSD& sd);
static std::list<std::string> loadShortCodes(const LLSD& sd);
void translateCategories(std::list<std::string>& categories);
private:
std::vector<LLEmojiGroup> mGroups;
std::list<LLEmojiDescriptor> mEmojis;
std::list<std::string> mSkipCategories;
cat2cat_map_t mTranslations;
cat2group_map_t mCategory2Group;
emoji2descr_map_t mEmoji2Descr;
cat2descrs_map_t mCategory2Descrs;
code2descr_map_t mShortCode2Descr;
};
// ============================================================================
+193
View File
@@ -0,0 +1,193 @@
/**
* @file llemojihelper.h
* @brief Header file for LLEmojiHelper
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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$
*/
#include "linden_common.h"
#include "llemojidictionary.h"
#include "llemojihelper.h"
#include "llfloater.h"
#include "llfloaterreg.h"
#include "lluictrl.h"
// ============================================================================
// Constants
//
constexpr char DEFAULT_EMOJI_HELPER_FLOATER[] = "emoji_picker";
constexpr S32 HELPER_FLOATER_OFFSET_X = 0;
constexpr S32 HELPER_FLOATER_OFFSET_Y = 0;
// ============================================================================
// LLEmojiHelper
//
std::string LLEmojiHelper::getToolTip(llwchar ch) const
{
return LLEmojiDictionary::instance().getNameFromEmoji(ch);
}
bool LLEmojiHelper::isActive(const LLUICtrl* ctrl_p) const
{
return mHostHandle.get() == ctrl_p;
}
// static
bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S32* pShortCodePos)
{
// <FS:PP> FIRE-33735: Option to suppress emoji chooser window from automatically popping up while typing in chat bars
static LLUICachedControl<bool> FSEnableEmojiWindowPopupWhileTyping("FSEnableEmojiWindowPopupWhileTyping");
if (!FSEnableEmojiWindowPopupWhileTyping)
{
return false;
}
// </FS:PP>
if (cursorPos < 0 || wtext.size() < cursorPos) return false; // <FS:Beq/> FIRE-33773 - fix logic to avoid OOB access to wtext
// If the cursor is currently on a colon start the check one character further back
S32 shortCodePos = (cursorPos == 0 || L':' != wtext[cursorPos - 1]) ? cursorPos : cursorPos - 1;
auto isPartOfShortcode = [](llwchar ch) {
switch (ch)
{
case L'-':
case L'_':
case L'+':
return true;
default:
return LLStringOps::isAlnum(ch);
}
};
while (shortCodePos > 1 && isPartOfShortcode(wtext[shortCodePos - 1]))
{
shortCodePos--;
}
bool isShortCode = (cursorPos - shortCodePos >= 2) && (L':' == wtext[shortCodePos - 1]);
if(isShortCode && (shortCodePos >= 2) && isdigit(wtext[shortCodePos - 2])) // <TS:3T> Add qualifier to avoid emoji pop-up when typing times.
isShortCode = false;
if (pShortCodePos)
*pShortCodePos = (isShortCode) ? shortCodePos - 1 : -1;
return isShortCode;
}
void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(llwchar)> cb)
{
// Commit immediately if the user already typed a full shortcode
if (const auto* emojiDescrp = LLEmojiDictionary::instance().getDescriptorFromShortCode(short_code))
{
cb(emojiDescrp->Character);
hideHelper();
return;
}
if (mHelperHandle.isDead())
{
LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER);
// <FS:Beq> Try to prevent failed build of emoji picker from killing the viewer.
if(!pHelperFloater)
{
LL_WARNS() << "Cannot show emoji helper, reason unknown." << LL_ENDL;
return;
}
// </FS:Beq>
mHelperHandle = pHelperFloater->getHandle();
mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())[0]); }, std::placeholders::_2));
}
setHostCtrl(hostctrl_p);
mEmojiCommitCb = cb;
S32 floater_x=0, floater_y=0;// <FS:Beq/> initialise to avoid warnings
if (hostctrl_p && !hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView))// <FS:Beq/> another unchecked pointer access
{
LL_WARNS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL; // <FS:Beq/> Is this really worth crashing over?
return;
}
LLFloater* pHelperFloater = mHelperHandle.get();
// <FS:Beq> Be a bit paranoid - the previous code should have ensured this or returned.
if (!pHelperFloater)
{
LL_WARNS() << "Helper floater unexpectedly null." << LL_ENDL;
return;
}
// </FS:Beq>
LLRect rect = pHelperFloater->getRect();
S32 left = floater_x - HELPER_FLOATER_OFFSET_X;
S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight();
rect.setLeftTopAndSize(left, top, rect.getWidth(), rect.getHeight());
pHelperFloater->setRect(rect);
pHelperFloater->openFloater(LLSD().with("hint", short_code));
}
void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p, bool strict)
{
mIsHideDisabled &= !strict;
if (mIsHideDisabled || (ctrl_p && !isActive(ctrl_p)))
{
return;
}
setHostCtrl(nullptr);
}
bool LLEmojiHelper::handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask)
{
if (mHelperHandle.isDead() || !isActive(ctrl_p))
{
return false;
}
return mHelperHandle.get()->handleKey(key, mask, true);
}
void LLEmojiHelper::onCommitEmoji(llwchar emoji)
{
if (!mHostHandle.isDead() && mEmojiCommitCb)
{
mEmojiCommitCb(emoji);
}
}
void LLEmojiHelper::setHostCtrl(LLUICtrl* hostctrl_p)
{
const LLUICtrl* pCurHostCtrl = mHostHandle.get();
if (pCurHostCtrl != hostctrl_p)
{
mHostCtrlFocusLostConn.disconnect();
mHostHandle.markDead();
mEmojiCommitCb = {};
if (!mHelperHandle.isDead())
{
mHelperHandle.get()->closeFloater();
}
if (hostctrl_p)
{
mHostHandle = hostctrl_p->getHandle();
mHostCtrlFocusLostConn = hostctrl_p->setFocusLostCallback(std::bind([&]() { hideHelper(getHostCtrl()); }));
}
}
}
+66
View File
@@ -0,0 +1,66 @@
/**
* @file llemojihelper.h
* @brief Header file for LLEmojiHelper
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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$
*/
#pragma once
#include "llhandle.h"
#include "llsingleton.h"
#include <boost/signals2.hpp>
class LLFloater;
class LLUICtrl;
class LLEmojiHelper : public LLSingleton<LLEmojiHelper>
{
LLSINGLETON(LLEmojiHelper) {}
~LLEmojiHelper() override {}
public:
// General
std::string getToolTip(llwchar ch) const;
bool isActive(const LLUICtrl* ctrl_p) const;
static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr);
void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(llwchar)> commit_cb);
void hideHelper(const LLUICtrl* ctrl_p = nullptr, bool strict = false);
void setIsHideDisabled(bool disabled) { mIsHideDisabled = disabled; };
// Eventing
bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask);
void onCommitEmoji(llwchar emoji);
protected:
LLUICtrl* getHostCtrl() const { return mHostHandle.get(); }
void setHostCtrl(LLUICtrl* hostctrl_p);
private:
LLHandle<LLUICtrl> mHostHandle;
LLHandle<LLFloater> mHelperHandle;
boost::signals2::connection mHostCtrlFocusLostConn;
boost::signals2::connection mHelperCommitConn;
std::function<void(llwchar)> mEmojiCommitCb;
bool mIsHideDisabled;
};
+51
View File
@@ -0,0 +1,51 @@
/**
* @file llf32uictrl.cpp
* @author Nat Goodspeed
* @date 2008-09-08
* @brief Implementation for llf32uictrl.
*
* $LicenseInfo:firstyear=2008&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$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "llf32uictrl.h"
// STL headers
// std headers
// external library headers
// other Linden headers
LLF32UICtrl::LLF32UICtrl(const Params& p)
: LLUICtrl(p),
mInitialValue((F32)p.initial_value().asReal()),
mMinValue(p.min_value),
mMaxValue(p.max_value),
mIncrement(p.increment)
{
mViewModel->setValue(p.initial_value);
}
F32 LLF32UICtrl::getValueF32() const
{
return (F32)mViewModel->getValue().asReal();
}
+77
View File
@@ -0,0 +1,77 @@
/**
* @file llf32uictrl.h
* @author Nat Goodspeed
* @date 2008-09-08
* @brief Base class for float-valued LLUICtrl widgets
*
* $LicenseInfo:firstyear=2008&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$
*/
#if ! defined(LL_LLF32UICTRL_H)
#define LL_LLF32UICTRL_H
#include "lluictrl.h"
class LLF32UICtrl: public LLUICtrl
{
public:
struct Params: public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<F32> min_value,
max_value,
increment;
Params()
: min_value("min_val", 0.f),
max_value("max_val", 1.f),
increment("increment", 0.1f)
{}
};
protected:
LLF32UICtrl(const Params& p);
public:
virtual F32 getValueF32() const;
virtual void setValue(const LLSD& value ) { mViewModel->setValue(value); }
virtual LLSD getValue() const { return LLSD(getValueF32()); }
virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); }
virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); }
virtual F32 getInitialValue() const { return mInitialValue; }
virtual F32 getMinValue() const { return mMinValue; }
virtual F32 getMaxValue() const { return mMaxValue; }
virtual F32 getIncrement() const { return mIncrement; }
virtual void setMinValue(F32 min_value) { mMinValue = min_value; }
virtual void setMaxValue(F32 max_value) { mMaxValue = max_value; }
virtual void setIncrement(F32 increment) { mIncrement = increment;}
protected:
F32 mInitialValue;
F32 mMinValue;
F32 mMaxValue;
F32 mIncrement;
};
#endif /* ! defined(LL_LLF32UICTRL_H) */
+46
View File
@@ -0,0 +1,46 @@
/**
* @file llfiltereditor.cpp
* @brief LLFilterEditor implementation
*
* $LicenseInfo:firstyear=2001&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$
*/
// Text editor widget to let users enter a single line.
#include "linden_common.h"
#include "llfiltereditor.h"
LLFilterEditor::LLFilterEditor(const LLFilterEditor::Params& p)
: LLSearchEditor(p)
{
setCommitOnFocusLost(false); // we'll commit on every keystroke, don't re-commit when we take focus away (i.e. we go to interact with the actual results!)
}
void LLFilterEditor::handleKeystroke()
{
this->LLSearchEditor::handleKeystroke();
// Commit on every keystroke.
onCommit();
}
+55
View File
@@ -0,0 +1,55 @@
/**
* @file llfiltereditor.h
* @brief Text editor widget that represents a filter operation
*
* Features:
* Text entry of a single line (text, delete, left and right arrow, insert, return).
* Callbacks either on every keystroke or just on the return key.
* Focus (allow multiple text entry widgets)
* Clipboard (cut, copy, and paste)
* Horizontal scrolling to allow strings longer than widget size allows
* Pre-validation (limit which keys can be used)
* Optional line history so previous entries can be recalled by CTRL UP/DOWN
*
* $LicenseInfo:firstyear=2001&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_FILTEREDITOR_H
#define LL_FILTEREDITOR_H
#include "llsearcheditor.h"
class LLFilterEditor : public LLSearchEditor
{
public:
struct Params : public LLInitParam::Block<Params, LLSearchEditor::Params>
{};
virtual ~LLFilterEditor() {}
protected:
LLFilterEditor(const Params&);
friend class LLUICtrlFactory;
/*virtual*/ void handleKeystroke();
};
#endif // LL_FILTEREDITOR_H
+120
View File
@@ -0,0 +1,120 @@
/**
* @file llflashtimer.cpp
* @brief LLFlashTimer class implementation
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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$
*/
#include "llflashtimer.h"
#include "lleventtimer.h"
#include "llui.h"
LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period)
: LLEventTimer(period),
mCallback(cb),
mCurrentTickCount(0),
mIsFlashingInProgress(false),
mIsCurrentlyHighlighted(false),
mUnset(false)
{
mEventTimer.stop();
// By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973.
// Due to Timer is implemented as derived class from EventTimer it is impossible to change period
// in runtime. So, both settings are made as required restart.
// <FS:CR>
//mFlashCount = 2 * ((count > 0) ? count : LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount"));
static LLCachedControl<S32> flash_count(*LLUI::getInstance()->mSettingGroups["config"], "FlashCount");
mFlashCount = 2 * ((count > 0) ? count : flash_count);
// </FS:CR>
if (mPeriod <= 0)
{
//mPeriod = LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod");
// <FS:CR>
static LLCachedControl<F32> flash_period(*LLUI::getInstance()->mSettingGroups["config"], "FlashPeriod");
mPeriod = flash_period;
// </FS:CR>
}
// <FS:Ansariel> Configurable at runtime
LLUI::getInstance()->mSettingGroups["config"]->getControl("FlashCount")->getSignal()->connect(boost::bind(&LLFlashTimer::onUpdateFlashSettings, this));
LLUI::getInstance()->mSettingGroups["config"]->getControl("FlashPeriod")->getSignal()->connect(boost::bind(&LLFlashTimer::onUpdateFlashSettings, this));
// </FS:Ansariel>
}
// <FS:Ansariel> Configurable at runtime
void LLFlashTimer::onUpdateFlashSettings()
{
stopFlashing();
mFlashCount = 2 * llmax(LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount"), 0);
mPeriod = llmax(LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod"), 0.f);
}
// </FS:Ansariel>
void LLFlashTimer::unset()
{
mUnset = true;
mCallback = NULL;
}
bool LLFlashTimer::tick()
{
mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted;
if (mCallback)
{
mCallback(mIsCurrentlyHighlighted);
}
if (++mCurrentTickCount >= mFlashCount)
{
stopFlashing();
}
return mUnset;
}
void LLFlashTimer::startFlashing()
{
mIsFlashingInProgress = true;
mIsCurrentlyHighlighted = true;
mEventTimer.start();
}
void LLFlashTimer::stopFlashing()
{
mEventTimer.stop();
mIsFlashingInProgress = false;
mIsCurrentlyHighlighted = false;
mCurrentTickCount = 0;
}
bool LLFlashTimer::isFlashingInProgress()
{
return mIsFlashingInProgress;
}
bool LLFlashTimer::isCurrentlyHighlighted()
{
return mIsCurrentlyHighlighted;
}
+77
View File
@@ -0,0 +1,77 @@
/**
* @file llflashtimer.h
* @brief LLFlashTimer class implementation
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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_FLASHTIMER_H
#define LL_FLASHTIMER_H
#include "lleventtimer.h"
#include "boost/function.hpp"
class LLFlashTimer : public LLEventTimer
{
public:
typedef boost::function<void (bool)> callback_t;
/**
* Constructor.
*
* @param count - how many times callback should be called (twice to not change original state)
* @param period - how frequently callback should be called
* @param cb - callback to be called each tick
*/
LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0);
~LLFlashTimer() {};
/*virtual*/ bool tick();
void startFlashing();
void stopFlashing();
bool isFlashingInProgress();
bool isCurrentlyHighlighted();
/*
* Use this instead of deleting this object.
* The next call to tick() will return true and that will destroy this object.
*/
void unset();
private:
// <FS:Ansariel> Configurable at runtime
void onUpdateFlashSettings();
callback_t mCallback;
/**
* How many times parent will blink.
*/
S32 mFlashCount;
S32 mCurrentTickCount;
bool mIsCurrentlyHighlighted;
bool mIsFlashingInProgress;
bool mUnset;
};
#endif /* LL_FLASHTIMER_H */
File diff suppressed because it is too large Load Diff
+549
View File
@@ -0,0 +1,549 @@
/**
* @file llflatlistview.h
* @brief LLFlatListView base class and extension to support messages for several cases of an empty list.
*
* $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_LLFLATLISTVIEW_H
#define LL_LLFLATLISTVIEW_H
#include "llpanel.h"
#include "llscrollcontainer.h"
#include "lltextbox.h"
/**
* LLFlatListView represents a flat list ui control that operates on items in a form of LLPanel's.
* LLSD can be associated with each added item, it can keep data from an item in digested form.
* Associated LLSD's can be of any type (singular, a map etc.).
* Items (LLPanel's subclasses) can be of different height.
* The list is LLPanel created in itself and grows in height while new items are added.
*
* The control can manage selection of its items when the flag "allow_select" is set. Also ability to select
* multiple items (by using CTRL) is enabled through setting the flag "multi_select" - if selection is not allowed that flag
* is ignored. The option "keep_one_selected" forces at least one item to be selected at any time (only for mouse events on items)
* since any item of the list was selected.
*
* Examples of using this control are presented in Picks panel (My Profile and Profile View), where this control is used to
* manage the list of pick items.
*
* ASSUMPTIONS AND STUFF
* - NULL pointers and undefined LLSD's are not accepted by any method of this class unless specified otherwise
* - Order of returned selected items are not guaranteed
* - The control assumes that all items being added are unique.
*/
class LLFlatListView : public LLScrollContainer, public LLEditMenuHandler
{
LOG_CLASS(LLFlatListView);
public:
/**
* Abstract comparator for comparing flat list items in a form of LLPanel
*/
class ItemComparator
{
public:
ItemComparator() {};
virtual ~ItemComparator() {};
/** Returns true if item1 < item2, false otherwise */
virtual bool compare(const LLPanel* item1, const LLPanel* item2) const = 0;
};
/**
* Represents reverse comparator which acts as a decorator for a comparator that need to be reversed
*/
class ItemReverseComparator : public ItemComparator
{
public:
ItemReverseComparator(const ItemComparator& comparator) : mComparator(comparator) {};
virtual ~ItemReverseComparator() {};
virtual bool compare(const LLPanel* item1, const LLPanel* item2) const
{
return mComparator.compare(item2, item1);
}
private:
const ItemComparator& mComparator;
};
struct Params : public LLInitParam::Block<Params, LLScrollContainer::Params>
{
/** turning on/off selection support */
Optional<bool> allow_select;
/** turning on/off multiple selection (works while clicking and holding CTRL)*/
Optional<bool> multi_select;
/** don't allow to deselect all selected items (for mouse events on items only) */
Optional<bool> keep_one_selected;
/** try to keep selection visible after reshape */
Optional<bool> keep_selection_visible_on_reshape;
/** padding between items */
Optional<U32> item_pad;
/** textbox with info message when list is empty*/
Optional<LLTextBox::Params> no_items_text;
//KC *hack*
Optional<U32> magical_hacky_height_padding;
Params();
};
// disable traversal when finding widget to hand focus off to
/*virtual*/ bool canFocusChildren() const { return false; }
/**
* Connects callback to signal called when Return key is pressed.
*/
boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); }
/**
* Override callback here to make sure double click events are not raised for the scroll bar -Zi
*/
boost::signals2::connection setDoubleClickCallback( const mouse_signal_t::slot_type& cb ) { return mItemsPanel->setDoubleClickCallback(cb); }
/** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */
virtual void reshape(S32 width, S32 height, bool called_from_parent = true);
/** Returns full rect of child panel */
const LLRect& getItemsRect() const;
LLRect getRequiredRect() { return getItemsRect(); }
/** Returns distance between items */
const S32 getItemsPad() { return mItemPad; }
/**
* Adds and item and LLSD value associated with it to the list at specified position
* @return true if the item was added, false otherwise
*/
virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM, bool rearrange = true);
/**
* Insert item_to_add along with associated value to the list right after the after_item.
* @return true if the item was successfully added, false otherwise
*/
virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value = LLUUID::null);
/**
* Remove specified item
* @return true if the item was removed, false otherwise
*/
virtual bool removeItem(LLPanel* item, bool rearrange = true);
/**
* Remove an item specified by value
* @return true if the item was removed, false otherwise
*/
virtual bool removeItemByValue(const LLSD& value, bool rearrange = true);
/**
* Remove an item specified by uuid
* @return true if the item was removed, false otherwise
*/
virtual bool removeItemByUUID(const LLUUID& uuid, bool rearrange = true);
/**
* Get an item by value
* @return the item as LLPanel if associated with value, NULL otherwise
*/
virtual LLPanel* getItemByValue(const LLSD& value) const;
template<class T>
T* getTypedItemByValue(const LLSD& value) const
{
return dynamic_cast<T*>(getItemByValue(value));
}
/**
* Select or deselect specified item based on select
* @return true if succeed, false otherwise
*/
virtual bool selectItem(LLPanel* item, bool select = true);
/**
* Select or deselect an item by associated value based on select
* @return true if succeed, false otherwise
*/
virtual bool selectItemByValue(const LLSD& value, bool select = true);
/**
* Select or deselect an item by associated uuid based on select
* @return true if succeed, false otherwise
*/
virtual bool selectItemByUUID(const LLUUID& uuid, bool select = true);
/**
* Get all panels stored in the list.
*/
virtual void getItems(std::vector<LLPanel*>& items) const;
/**
* Get all items values.
*/
virtual void getValues(std::vector<LLSD>& values) const;
/**
* Get LLSD associated with the first selected item
*/
virtual LLSD getSelectedValue() const;
/**
* Get LLSD's associated with selected items.
* @param selected_values std::vector being populated with LLSD associated with selected items
*/
virtual void getSelectedValues(std::vector<LLSD>& selected_values) const;
/**
* Get LLUUID associated with selected item
* @return LLUUID if such was associated with selected item
*/
virtual LLUUID getSelectedUUID() const;
/**
* Get LLUUIDs associated with selected items
* @param selected_uuids An std::vector being populated with LLUUIDs associated with selected items
*/
virtual void getSelectedUUIDs(uuid_vec_t& selected_uuids) const;
/** Get the top selected item */
virtual LLPanel* getSelectedItem() const;
/**
* Get selected items
* @param selected_items An std::vector being populated with pointers to selected items
*/
virtual void getSelectedItems(std::vector<LLPanel*>& selected_items) const;
/**
* Resets selection of items.
*
* It calls onCommit callback if setCommitOnSelectionChange(bool b) was called with "true"
* argument for current Flat List.
* @param no_commit_on_deselection - if true onCommit callback will not be called
*/
virtual void resetSelection(bool no_commit_on_deselection = false);
/**
* Sets comment text which will be shown in the list is it is empty.
*
* Textbox to hold passed text is created while this method is called at the first time.
*
* @param comment_text - string to be shown as a comment.
*/
void setNoItemsCommentText( const std::string& comment_text);
/** Turn on/off multiple selection support */
void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; }
/** Turn on/off selection support */
void setAllowSelection(bool can_select) { mAllowSelection = can_select; }
/** Sets flag whether onCommit should be fired if selection was changed */
// FIXME: this should really be a separate signal, since "Commit" implies explicit user action, and selection changes can happen more indirectly.
void setCommitOnSelectionChange(bool b) { mCommitOnSelectionChange = b; }
/** Get number of selected items in the list */
U32 numSelected() const {return static_cast<U32>(mSelectedItemPairs.size()); }
/** Get number of (visible) items in the list */
U32 size(const bool only_visible_items = true) const;
/** Removes all items from the list */
virtual void clear();
/**
* Removes all items that can be detached from the list but doesn't destroy
* them, caller responsible to manage items after they are detached.
* Detachable item should accept "detach" action via notify() method,
* where it disconnect all callbacks, does other valuable routines and
* return 1.
*/
void detachItems(std::vector<LLPanel*>& detached_items);
/**
* Set comparator to use for future sorts.
*
* This class does NOT manage lifetime of the comparator
* but assumes that the comparator is always alive.
*/
void setComparator(const ItemComparator* comp) { mItemComparator = comp; }
void sort();
bool updateValue(const LLSD& old_value, const LLSD& new_value);
void scrollToShowFirstSelectedItem();
void selectFirstItem ();
void selectLastItem ();
virtual S32 notify(const LLSD& info) ;
virtual ~LLFlatListView();
protected:
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
typedef std::pair<LLPanel*, LLSD> item_pair_t;
typedef std::list<item_pair_t*> pairs_list_t;
typedef pairs_list_t::iterator pairs_iterator_t;
typedef pairs_list_t::const_iterator pairs_const_iterator_t;
/** An adapter for a ItemComparator */
struct ComparatorAdaptor
{
ComparatorAdaptor(const ItemComparator& comparator) : mComparator(comparator) {};
bool operator()(const item_pair_t* item_pair1, const item_pair_t* item_pair2)
{
return mComparator.compare(item_pair1->first, item_pair2->first);
}
const ItemComparator& mComparator;
};
friend class LLUICtrlFactory;
LLFlatListView(const LLFlatListView::Params& p);
/** Manage selection on mouse events */
void onItemMouseClick(item_pair_t* item_pair, MASK mask);
void onItemRightMouseClick(item_pair_t* item_pair, MASK mask);
/**
* Updates position of items.
* It does not take into account invisible items.
*/
virtual void rearrangeItems();
virtual item_pair_t* getItemPair(LLPanel* item) const;
virtual item_pair_t* getItemPair(const LLSD& value) const;
virtual bool selectItemPair(item_pair_t* item_pair, bool select);
virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection);
virtual bool canSelectAll() const;
virtual void selectAll();
virtual bool isSelected(item_pair_t* item_pair) const;
virtual bool removeItemPair(item_pair_t* item_pair, bool rearrange);
bool addItemPairs(pairs_list_t panel_list, bool rearrange = true);
/**
* Notify parent about changed size of internal controls with "size_changes" action
*
* Size includes Items Rect width and either Items Rect height or comment text height.
* Comment text height is included if comment text is set and visible.
* List border size is also included into notified size.
*/
void notifyParentItemsRectChanged();
virtual bool handleKeyHere(KEY key, MASK mask);
virtual bool postBuild();
virtual void onFocusReceived();
virtual void onFocusLost();
virtual void draw();
LLRect getLastSelectedItemRect();
void ensureSelectedVisible();
const pairs_list_t& getItemPairs() { return mItemPairs; }
private:
void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;}
void setNoItemsCommentVisible(bool visible) const;
protected:
/** Comparator to use when sorting the list. */
const ItemComparator* mItemComparator;
private:
LLPanel* mItemsPanel;
S32 mItemsNoScrollWidth;
S32 mBorderThickness;
/** Items padding */
S32 mItemPad;
/** Selection support flag */
bool mAllowSelection;
/** Multiselection support flag, ignored if selection is not supported */
bool mMultipleSelection;
/**
* Flag specified whether onCommit be called if selection is changed in the list.
*
* Can be ignored in the resetSelection() method.
* @see resetSelection()
*/
bool mCommitOnSelectionChange;
bool mKeepOneItemSelected;
bool mIsConsecutiveSelection;
bool mKeepSelectionVisibleOnReshape;
/** All pairs of the list */
pairs_list_t mItemPairs;
/** Selected pairs for faster access */
pairs_list_t mSelectedItemPairs;
/**
* Rectangle contained previous size of items parent notified last time.
* Is used to reduce amount of parentNotify() calls if size was not changed.
*/
LLRect mPrevNotifyParentRect;
LLTextBox* mNoItemsCommentTextbox;
LLViewBorder* mSelectedItemsBorder;
commit_signal_t mOnReturnSignal;
//KC *hack*
S32 mMagicalHackyHeightPadding;
};
/**
* Extends LLFlatListView functionality to show different messages when there are no items in the
* list depend on whether they are filtered or not.
*
* Class provides one message per case of empty list.
* It also provides protected updateNoItemsMessage() method to be called each time when derived list
* is changed to update base mNoItemsCommentTextbox value.
*
* It is implemented to avoid duplication of this functionality in concrete implementations of the
* lists. It is intended to be used as a base class for lists which should support two different
* messages for empty state. Can be improved to support more than two messages via state-to-message map.
*/
class LLFlatListViewEx : public LLFlatListView
{
public:
LOG_CLASS(LLFlatListViewEx);
struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
{
/**
* Contains a message for empty list when it does not contain any items at all.
*/
Optional<std::string> no_items_msg;
/**
* Contains a message for empty list when its items are removed by filtering.
*/
Optional<std::string> no_filtered_items_msg;
Params();
};
// *WORKAROUND: two methods to overload appropriate Params due to localization issue:
// no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931
// [RLVa:KB] - Checked: RLVa-2.0.3
const std::string& getNoItemsMsg() const { return mNoItemsMsg; }
// [/RLVa:KB]
void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; }
void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; }
bool getForceShowingUnmatchedItems();
void setForceShowingUnmatchedItems(bool show);
/**
* Sets up new filter string and filters the list.
*/
void setFilterSubString(const std::string& filter_str, bool notify_parent);
std::string getFilterSubString() { return mFilterSubString; }
/**
* Filters the list, rearranges and notifies parent about shape changes.
* Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration.
*/
void filterItems(bool re_sort, bool notify_parent);
/**
* Returns true if last call of filterItems() found at least one matching item
*/
bool hasMatchedItems();
protected:
LLFlatListViewEx(const Params& p);
/**
* Applies a message for empty list depend on passed argument.
*
* @param filter_string - if is not empty, message for filtered items will be set, otherwise for
* completely empty list. Value of filter string will be passed as search_term in SLURL.
*/
void updateNoItemsMessage(const std::string& filter_string);
/**
* Applies visibility acording to action and LLFlatListView settings.
*
* @param item - item we are changing
* @param item - action - parameters to determin visibility from
*/
bool updateItemVisibility(LLPanel* item, const LLSD &action);
private:
std::string mNoFilteredItemsMsg;
std::string mNoItemsMsg;
std::string mFilterSubString;
/**
* Show list items that don't match current filter
*/
bool mForceShowingUnmatchedItems;
/**
* True if last call of filterItems() found at least one matching item
*/
bool mHasMatchedItems;
};
#endif
File diff suppressed because it is too large Load Diff
+693
View File
@@ -0,0 +1,693 @@
/**
* @file llfloater.h
* @brief LLFloater base class
*
* $LicenseInfo:firstyear=2002&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$
*/
// Floating "windows" within the GL display, like the inventory floater,
// mini-map floater, etc.
#ifndef LL_FLOATER_H
#define LL_FLOATER_H
#include "llpanel.h"
#include "lltoolbar.h"
#include "lluuid.h"
//#include "llnotificationsutil.h"
#include <set>
#include <boost/signals2.hpp>
class LLDragHandle;
class LLResizeHandle;
class LLResizeBar;
class LLButton;
class LLMultiFloater;
class LLFloater;
const bool RESIZE_YES = true;
const bool RESIZE_NO = false;
const bool DRAG_ON_TOP = false;
const bool DRAG_ON_LEFT = true;
const bool MINIMIZE_YES = true;
const bool MINIMIZE_NO = false;
const bool CLOSE_YES = true;
const bool CLOSE_NO = false;
const bool ADJUST_VERTICAL_YES = true;
const bool ADJUST_VERTICAL_NO = false;
const F32 CONTEXT_CONE_IN_ALPHA = 0.f;
const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
const F32 CONTEXT_CONE_FADE_TIME = .08f;
namespace LLFloaterEnums
{
enum EOpenPositioning
{
POSITIONING_RELATIVE,
POSITIONING_CASCADING,
POSITIONING_CASCADE_GROUP,
POSITIONING_CENTERED,
POSITIONING_SPECIFIED,
POSITIONING_COUNT
};
}
namespace LLInitParam
{
template<>
struct TypeValues<LLFloaterEnums::EOpenPositioning> : public TypeValuesHelper<LLFloaterEnums::EOpenPositioning>
{
static void declareValues();
};
}
struct LL_COORD_FLOATER
{
typedef F32 value_t;
LLCoordCommon convertToCommon() const;
void convertFromCommon(const LLCoordCommon& from);
protected:
LLHandle<LLFloater> mFloater;
};
struct LLCoordFloater : LLCoord<LL_COORD_FLOATER>
{
typedef LLCoord<LL_COORD_FLOATER> coord_t;
LLCoordFloater() {}
LLCoordFloater(F32 x, F32 y, LLFloater& floater);
LLCoordFloater(const LLCoordCommon& other, LLFloater& floater);
LLCoordFloater& operator=(const LLCoordCommon& other)
{
convertFromCommon(other);
return *this;
}
LLCoordFloater& operator=(const LLCoordFloater& other);
bool operator==(const LLCoordFloater& other) const;
bool operator!=(const LLCoordFloater& other) const { return !(*this == other); }
void setFloater(LLFloater& floater);
};
class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater>
{
friend class LLFloaterView;
friend class LLFloaterReg;
friend class LLMultiFloater;
public:
struct KeyCompare
{
// static bool compare(const LLSD& a, const LLSD& b);
static bool equate(const LLSD& a, const LLSD& b);
/*==========================================================================*|
bool operator()(const LLSD& a, const LLSD& b) const
{
return compare(a, b);
}
|*==========================================================================*/
};
enum EFloaterButton
{
BUTTON_CLOSE = 0,
// <FS:Ansariel> FIRE-11724: Snooze group chat
BUTTON_SNOOZE,
// </FS:Ansariel>
BUTTON_RESTORE,
BUTTON_MINIMIZE,
BUTTON_TEAR_OFF,
BUTTON_DOCK,
BUTTON_HELP,
BUTTON_COUNT
};
struct Params
: public LLInitParam::Block<Params, LLPanel::Params>
{
Optional<std::string> title,
short_title;
Optional<bool> single_instance,
reuse_instance,
can_resize,
can_minimize,
can_close,
can_snooze, // <FS:Ansariel> FIRE-11724: Snooze group chat
can_drag_on_left,
can_tear_off,
drop_shadow, // ## Zi: Optional Drop Shadows
save_rect,
save_visibility,
save_dock_state,
can_dock,
show_title,
auto_close;
Optional<LLFloaterEnums::EOpenPositioning> positioning;
Optional<S32> header_height,
label_v_padding, // <FS:Zi> Make vertical label padding a per-skin option
legacy_header_height; // HACK see initFromXML()
Optional<F32> rel_x,
rel_y;
// Images for top-right controls
Optional<LLUIImage*> close_image,
snooze_image, // <FS:Ansariel> FIRE-11724: Snooze group chat
restore_image,
minimize_image,
tear_off_image,
dock_image,
help_image;
Optional<LLUIImage*> close_pressed_image,
snooze_pressed_image, // <FS:Ansariel> FIRE-11724: Snooze group chat
restore_pressed_image,
minimize_pressed_image,
tear_off_pressed_image,
dock_pressed_image,
help_pressed_image;
Optional<CommitCallbackParam> open_callback,
close_callback;
Ignored follows;
Optional<bool> hosted_floater_show_titlebar; // <FS:Ansariel> MultiFloater without titlebar for hosted floater
Params();
};
// use this to avoid creating your own default LLFloater::Param instance
static const Params& getDefaultParams();
// Load translations for tooltips for standard buttons
static void initClass();
LLFloater(const LLSD& key, const Params& params = getDefaultParams());
virtual ~LLFloater();
// Don't export top/left for rect, only height/width
static void setupParamsForExport(Params& p, LLView* parent);
bool buildFromFile(const std::string &filename);
boost::signals2::connection setMinimizeCallback( const commit_signal_t::slot_type& cb );
boost::signals2::connection setOpenCallback( const commit_signal_t::slot_type& cb );
boost::signals2::connection setCloseCallback( const commit_signal_t::slot_type& cb );
void initFromParams(const LLFloater::Params& p);
bool initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node = NULL);
/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false);
/*virtual*/ bool canSnapTo(const LLView* other_view);
/*virtual*/ void setSnappedTo(const LLView* snap_view);
/*virtual*/ void setFocus( bool b );
/*virtual*/ void setIsChrome(bool is_chrome);
/*virtual*/ void setRect(const LLRect &rect);
void setIsSingleInstance(bool is_single_instance);
bool getIsSingleInstance() { return mSingleInstance; }
void initFloater(const Params& p);
void openFloater(const LLSD& key = LLSD());
// If allowed, close the floater cleanly, releasing focus.
virtual void closeFloater(bool app_quitting = false);
// Close the floater or its host. Use when hidding or toggling a floater instance.
virtual void closeHostedFloater();
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true);
/*virtual*/ void translate(S32 x, S32 y);
// Release keyboard and mouse focus
void releaseFocus();
// moves to center of gFloaterView
void center();
LLMultiFloater* getHost();
bool isDetachedAndNotMinimized();
void applyTitle();
std::string getCurrentTitle() const;
void setTitle( const std::string& title);
std::string getTitle() const;
void setShortTitle( const std::string& short_title );
std::string getShortTitle() const;
virtual void setMinimized(bool b);
void moveResizeHandlesToFront();
void addDependentFloater(LLFloater* dependent, bool reposition = true, bool resize = false);
void addDependentFloater(LLHandle<LLFloater> dependent_handle, bool reposition = true, bool resize = false);
LLFloater* getDependee() { return (LLFloater*)mDependeeHandle.get(); }
void removeDependentFloater(LLFloater* dependent);
// <FS:Ansariel> Fix floater relocation
//void fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels);
void fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& chatbar, const LLRect& utilitybar, const LLRect& constraint, S32 min_overlap_pixels);
// </FS:Ansariel>
bool isMinimized() const { return mMinimized; }
/// isShown() differs from getVisible() in that isShown() also considers
/// isMinimized(). isShown() is true only if visible and not minimized.
bool isShown() const;
/// The static isShown() can accept a NULL pointer (which of course
/// returns false). When non-NULL, it calls the non-static isShown().
static bool isShown(const LLFloater* floater);
static bool isVisible(const LLFloater* floater);
static bool isMinimized(const LLFloater* floater);
bool isFirstLook() { return mFirstLook; } // EXT-2653: This function is necessary to prevent overlapping for secondary showed toasts
virtual bool isFrontmost();
bool isDependent() { return !mDependeeHandle.isDead(); }
void setCanMinimize(bool can_minimize);
void setCanClose(bool can_close);
void setCanTearOff(bool can_tear_off);
virtual void setCanResize(bool can_resize);
void setCanDrag(bool can_drag);
bool getCanDrag();
void setCanSnooze(bool can_snooze); // <FS:Ansariel> FIRE-11724: Snooze group chat
void setHost(LLMultiFloater* host);
bool isResizable() const { return mResizable; }
void setResizeLimits( S32 min_width, S32 min_height );
void getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; }
static std::string getControlName(const std::string& name, const LLSD& key);
static LLControlGroup* getControlGroup();
bool isMinimizeable() const{ return mCanMinimize; }
bool isCloseable() const{ return mCanClose; }
bool isDragOnLeft() const{ return mDragOnLeft; }
S32 getMinWidth() const{ return mMinWidth; }
S32 getMinHeight() const{ return mMinHeight; }
S32 getHeaderHeight() const { return mHeaderHeight; }
virtual bool handleMouseDown(S32 x, S32 y, MASK mask);
virtual bool handleMouseUp(S32 x, S32 y, MASK mask);
virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask);
virtual bool handleDoubleClick(S32 x, S32 y, MASK mask);
virtual bool handleMiddleMouseDown(S32 x, S32 y, MASK mask);
virtual bool handleScrollWheel(S32 x, S32 y, S32 mask);
virtual void draw();
virtual void drawShadow(LLPanel* panel);
virtual void onOpen(const LLSD& key) {}
virtual void onClose(bool app_quitting) {}
virtual void onSnooze() {} // <FS:Ansariel> FIRE-11724: Snooze group chat
// This cannot be "const" until all derived floater canClose()
// methods are const as well. JC
virtual bool canClose() { return true; }
/*virtual*/ void setVisible(bool visible); // do not override
/*virtual*/ void onVisibilityChange ( bool new_visibility ); // do not override
bool canFocusStealFrontmost() const { return mFocusStealsFrontmost; }
void setFocusStealsFrontmost(bool wants_frontmost) { mFocusStealsFrontmost = wants_frontmost; }
void setFrontmost(bool take_focus = true, bool restore = true);
virtual void setVisibleAndFrontmost(bool take_focus = true, const LLSD& key = LLSD());
// Defaults to false.
virtual bool canSaveAs() const { return false; }
virtual void saveAs() {}
void setSnapTarget(LLHandle<LLFloater> handle) { mSnappedTo = handle; }
void clearSnapTarget() { mSnappedTo.markDead(); }
LLHandle<LLFloater> getSnapTarget() const { return mSnappedTo; }
LLHandle<LLFloater> getHandle() const { return getDerivedHandle<LLFloater>(); }
const LLSD& getKey() { return mKey; }
virtual bool matchesKey(const LLSD& key) { return mSingleInstance || KeyCompare::equate(key, mKey); }
const std::string& getInstanceName() { return mInstanceName; }
bool isDockable() const { return mCanDock; }
void setCanDock(bool b);
bool isDocked() const { return mDocked; }
virtual void setDocked(bool docked, bool pop_on_undock = true);
virtual void setTornOff(bool torn_off) { mTornOff = torn_off; }
bool isTornOff() {return mTornOff;}
void setOpenPositioning(LLFloaterEnums::EOpenPositioning pos) {mPositioning = pos;}
// Close the floater returned by getFrontmostClosableFloater() and
// handle refocusing.
static void closeFrontmostFloater();
static bool isQuitRequested() { return sQuitting; }
// LLNotification::Params contextualNotification(const std::string& name)
// {
// return LLNotification::Params(name).context(mNotificationContext);
// }
static void onClickClose(LLFloater* floater);
static void onClickClose(LLFloater* floater, bool app_quitting);
static void onClickMinimize(LLFloater* floater);
static void onClickTearOff(LLFloater* floater);
static void onClickDock(LLFloater* floater);
static void onClickHelp(LLFloater* floater);
static void onClickSnooze(LLFloater* floater); // <FS:Ansariel> FIRE-11724: Snooze group chat
static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; }
static LLMultiFloater* getFloaterHost() {return sHostp; }
void updateTransparency(ETypeTransparency transparency_type);
void enableResizeCtrls(bool enable, bool width = true, bool height = true);
bool isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mPositioning); }
// <COLOSI opensim multi-currency support>
// update currency symbols in titles (if there) and force update of display
void updateCurrencySymbols() { mTitle.updateCurrencySymbols(); mShortTitle.updateCurrencySymbols(); applyTitle(); }
// </COLOSI opensim multi-currency support>
protected:
void applyControlsAndPosition(LLFloater* other);
void stackWith(LLFloater& other);
virtual void initRectControl();
virtual bool applyRectControl();
bool applyDockState();
void applyPositioning(LLFloater* other, bool on_open);
void applyRelativePosition();
void storeRectControl();
void storeVisibilityControl();
void storeDockStateControl();
void setKey(const LLSD& key);
void setInstanceName(const std::string& name);
virtual void bringToFront(S32 x, S32 y);
virtual void goneFromFront();
void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized
const LLRect& getExpandedRect() const { return mExpandedRect; }
void setAutoFocus(bool focus) { mAutoFocus = focus; } // whether to automatically take focus when opened
bool getAutoFocus() const { return mAutoFocus; }
LLDragHandle* getDragHandle() const { return mDragHandle; }
void destroy(); // Don't call this directly. You probably want to call closeFloater()
virtual void onClickCloseBtn(bool app_quitting = false);
virtual void updateTitleButtons();
// Draws a cone from this floater to parent floater or view (owner)
// Modifies context_cone_opacity (interpolates according to fade time and returns new value)
void drawConeToOwner(F32 &context_cone_opacity,
F32 max_cone_opacity,
LLView *owner_view,
F32 context_fade_time = CONTEXT_CONE_FADE_TIME,
F32 contex_cone_in_alpha = CONTEXT_CONE_IN_ALPHA,
F32 contex_cone_out_alpha = CONTEXT_CONE_OUT_ALPHA);
private:
void setForeground(bool b); // called only by floaterview
void cleanupHandles(); // remove handles to dead floaters
void createMinimizeButton();
void buildButtons(const Params& p);
// Images and tooltips are named in the XML, but we want to look them
// up by index.
static LLUIImage* getButtonImage(const Params& p, EFloaterButton e);
static LLUIImage* getButtonPressedImage(const Params& p, EFloaterButton e);
/**
* @params is_chrome - if floater is Chrome it means that floater will never get focus.
* Therefore it can't be closed with 'Ctrl+W'. So the tooltip text of close button( X )
* should be 'Close' not 'Close(Ctrl+W)' as for usual floaters.
*/
static std::string getButtonTooltip(const Params& p, EFloaterButton e, bool is_chrome);
bool offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index);
void addResizeCtrls();
void layoutResizeCtrls();
void addDragHandle();
void layoutDragHandle(); // repair layout
static void updateActiveFloaterTransparency();
static void updateInactiveFloaterTransparency();
void updateTransparency(LLView* view, ETypeTransparency transparency_type);
public:
static const F32 CONTEXT_CONE_IN_ALPHA;
static const F32 CONTEXT_CONE_OUT_ALPHA;
static const F32 CONTEXT_CONE_FADE_TIME;
// Called when floater is opened, passes mKey
// Public so external views or floaters can watch for this floater opening
commit_signal_t mOpenSignal;
// Called when floater is closed, passes app_qitting as LLSD()
// Public so external views or floaters can watch for this floater closing
commit_signal_t mCloseSignal;
commit_signal_t* mMinimizeSignal;
protected:
bool mSaveRect;
bool mDefaultRectForGroup;
std::string mRectControl;
std::string mPosXControl;
std::string mPosYControl;
std::string mVisibilityControl;
std::string mDocStateControl;
LLSD mKey; // Key used for retrieving instances; set (for now) by LLFLoaterReg
LLDragHandle* mDragHandle;
LLResizeBar* mResizeBar[4];
LLResizeHandle* mResizeHandle[4];
LLButton* mButtons[BUTTON_COUNT];
// <FS:Ansariel> Make this accessible from child classes
std::string mInstanceName; // Store the instance name so we can remove ourselves from the list
private:
LLRect mExpandedRect;
LLUIString mTitle;
LLUIString mShortTitle;
bool mSingleInstance; // true if there is only ever one instance of the floater
bool mReuseInstance; // true if we want to hide the floater when we close it instead of destroying it
bool mIsReuseInitialized; // true if mReuseInstance already set from parameters
// <FS:Ansariel> Make this accessible from child classes
//std::string mInstanceName; // Store the instance name so we can remove ourselves from the list
bool mDropShadow; // ## Zi: Optional Drop Shadows
S32 mLabelVPadding; // <FS:Zi> Make vertical label padding a per-skin option
bool mCanTearOff;
bool mCanMinimize;
bool mCanClose;
bool mFocusStealsFrontmost = true; // false if we don't want the currently focused floater to cover this floater without user interaction
bool mDragOnLeft;
bool mResizable;
bool mAutoClose;
bool mCanSnooze; // <FS:Ansariel> FIRE-11724: Snooze group chat
LLFloaterEnums::EOpenPositioning mPositioning;
LLCoordFloater mPosition;
S32 mMinWidth;
S32 mMinHeight;
S32 mHeaderHeight; // height in pixels of header for title, drag bar
S32 mLegacyHeaderHeight;// HACK see initFloaterXML()
bool mMinimized;
bool mForeground;
LLHandle<LLFloater> mDependeeHandle;
bool mFirstLook; // true if the _next_ time this floater is visible will be the first time in the session that it is visible.
typedef std::set<LLHandle<LLFloater> > handle_set_t;
typedef std::set<LLHandle<LLFloater> >::iterator handle_set_iter_t;
handle_set_t mDependents;
bool mTranslateWithDependents { false };
bool mButtonsEnabled[BUTTON_COUNT];
F32 mButtonScale;
bool mAutoFocus;
LLHandle<LLFloater> mSnappedTo;
LLHandle<LLFloater> mHostHandle;
LLHandle<LLFloater> mLastHostHandle;
bool mCanDock;
bool mDocked;
bool mTornOff;
static LLMultiFloater* sHostp;
static bool sQuitting;
static std::string sButtonNames[BUTTON_COUNT];
static std::string sButtonToolTips[BUTTON_COUNT];
static std::string sButtonToolTipsIndex[BUTTON_COUNT];
typedef void(*click_callback)(LLFloater*);
static click_callback sButtonCallbacks[BUTTON_COUNT];
bool mHasBeenDraggedWhileMinimized;
S32 mPreviousMinimizedBottom;
S32 mPreviousMinimizedLeft;
F32 mDefaultRelativeX;
F32 mDefaultRelativeY;
// <FS:Ansariel> MultiFloater without titlebar for hosted floater
bool mHostedFloaterShowtitlebar;
};
/////////////////////////////////////////////////////////////
// LLFloaterView
// Parent of all floating panels
const S32 FLOATER_MIN_VISIBLE_PIXELS = 16;
class LLFloaterView : public LLUICtrl
{
public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>{};
protected:
LLFloaterView (const Params& p);
friend class LLUICtrlFactory;
public:
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true);
/*virtual*/ void draw();
/*virtual*/ LLRect getSnapRect() const;
/*virtual*/ void refresh();
LLRect findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor );
// Given a child of gFloaterView, make sure this view can fit entirely onscreen.
void adjustToFitScreen(LLFloater* floater, bool allow_partial_outside, bool snap_in_toolbars = false);
void setMinimizePositionVerticalOffset(S32 offset) { mMinimizePositionVOffset = offset; }
void getMinimizePosition( S32 *left, S32 *bottom);
void restoreAll(); // un-minimize all floaters
typedef std::set<LLView*> skip_list_t;
void pushVisibleAll(bool visible, const skip_list_t& skip_list = skip_list_t());
void popVisibleAll(const skip_list_t& skip_list = skip_list_t());
void setCycleMode(bool mode) { mFocusCycleMode = mode; }
bool getCycleMode() const { return mFocusCycleMode; }
void bringToFront( LLFloater* child, bool give_focus = true, bool restore = true );
void highlightFocusedFloater();
void unhighlightFocusedFloater();
void focusFrontFloater();
void destroyAllChildren();
// attempt to close all floaters
void closeAllChildren(bool app_quitting);
bool allChildrenClosed();
void shiftFloaters(S32 x_offset, S32 y_offset);
void hideAllFloaters();
void showHiddenFloaters();
LLFloater* getFrontmost() const;
LLFloater* getBackmost() const;
LLFloater* getParentFloater(LLView* viewp) const;
LLFloater* getFocusedFloater() const;
void syncFloaterTabOrder();
// Returns z order of child provided. 0 is closest, larger numbers
// are deeper in the screen. If there is no such child, the return
// value is not defined.
S32 getZOrder(LLFloater* child);
void setFloaterSnapView(LLHandle<LLView> snap_view) {mSnapView = snap_view; }
LLFloater* getFrontmostClosableFloater();
// <FS:KC> Fix for bad edge snapping
void setSnapOffsetBottom(S32 offset) { mSnapOffsetBottom = offset; }
void setSnapOffsetChatBar(S32 offset) { mSnapOffsetChatBar = offset; }
void setSnapOffsetRight(S32 offset) { mSnapOffsetRight = offset; }
void setSnapOffsetLeft(S32 offset) { mSnapOffsetLeft = offset; }
// </FS:KC> Fix for bad edge snapping
void setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect);
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
void setMainChatbarRect(LLLayoutPanel* panel, const LLRect& chatbar_rect);
void setUtilityBarRect(LLLayoutPanel* panel, const LLRect& utility_bar_rect);
const LLRect& getMainChatbarRect() const { return mMainChatbarRect; }
const LLRect& getUtilityBarRect() const { return mUtilityBarRect; }
const LLRect& getToolbarRect(LLToolBarEnums::EToolBarLocation tb) const;
private:
void hiddenFloaterClosed(LLFloater* floater);
LLRect mLastSnapRect;
LLRect mToolbarLeftRect;
LLRect mToolbarBottomRect;
LLRect mToolbarRightRect;
LLHandle<LLView> mSnapView;
bool mFocusCycleMode;
S32 mSnapOffsetBottom;
S32 mSnapOffsetChatBar; // <FS:KC> Fix for bad edge snapping
S32 mSnapOffsetLeft; // <FS:KC> Fix for bad edge snapping
S32 mSnapOffsetRight;
S32 mMinimizePositionVOffset;
typedef std::vector<std::pair<LLHandle<LLFloater>, boost::signals2::connection> > hidden_floaters_t;
hidden_floaters_t mHiddenFloaters;
LLHandle<LLFloater> mFrontChildHandle;
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
LLRect mMainChatbarRect;
LLRect mUtilityBarRect;
};
//
// Globals
//
extern LLFloaterView* gFloaterView;
#endif // LL_FLOATER_H
+687
View File
@@ -0,0 +1,687 @@
/**
* @file llfloaterreg.cpp
* @brief LLFloaterReg Floater Registration Class
*
* $LicenseInfo:firstyear=2002&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$
*/
#include "linden_common.h"
#include "llfloaterreg.h"
//#include "llagent.h"
#include "llfloater.h"
#include "llmultifloater.h"
#include "llfloaterreglistener.h"
#include "lluiusage.h"
#include <string>
//*******************************************************
//static
LLFloaterReg::instance_list_t LLFloaterReg::sNullInstanceList;
LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
std::map<std::string, std::string, std::less<>> LLFloaterReg::sGroupMap;
bool LLFloaterReg::sBlockShowFloaters = false;
std::set<std::string, std::less<>> LLFloaterReg::sAlwaysShowableList;
static LLFloaterRegListener sFloaterRegListener;
// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a
LLFloaterReg::validate_signal_t LLFloaterReg::mValidateSignal;
// [/RLVa:KB]
//*******************************************************
//static
void LLFloaterReg::add(const std::string& name, const std::string& filename, const LLFloaterBuildFunc& func, const std::string& groupname)
{
sBuildMap[name].mFunc = func;
sBuildMap[name].mFile = filename;
sGroupMap[name] = groupname.empty() ? name : groupname;
sGroupMap[groupname] = groupname; // for referencing directly by group name
}
//static
bool LLFloaterReg::isRegistered(std::string_view name)
{
return sBuildMap.find(name) != sBuildMap.end();
}
//static
LLFloater* LLFloaterReg::getLastFloaterInGroup(std::string_view name)
{
auto it = sGroupMap.find(name);
if (it != sGroupMap.end())
{
const std::string& groupname = it->second;
if (!groupname.empty())
{
instance_list_t& list = sInstanceMap[groupname];
if (!list.empty())
{
for (instance_list_t::reverse_iterator iter = list.rbegin(), end = list.rend(); iter != end; ++iter)
{
LLFloater* inst = *iter;
if (inst->getVisible() && !inst->isMinimized())
{
return inst;
}
}
}
}
}
return NULL;
}
// <FS:Ansariel> FIRE-24125: Add option to close all floaters of a group
//static
LLFloaterReg::instance_list_t LLFloaterReg::getAllFloatersInGroup(LLFloater* floater)
{
if (floater)
{
for (const auto& group : sGroupMap)
{
const std::string& group_name = group.second;
if (group_name.empty())
{
continue;
}
instance_list_t& instances = sInstanceMap[group_name];
for (auto instance : instances)
{
if (instance == floater)
{
return sInstanceMap[group_name];
}
}
}
}
return {};
}
// </FS:Ansariel>
LLFloater* LLFloaterReg::getLastFloaterCascading()
{
LLRect candidate_rect;
candidate_rect.mTop = 100000;
LLFloater* candidate_floater = NULL;
std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
for( ; it != it_end; ++it)
{
const std::string& group_name = it->second;
instance_list_t& instances = sInstanceMap[group_name];
for (LLFloater* inst : instances)
{
if (inst->getVisible()
&& (inst->isPositioning(LLFloaterEnums::POSITIONING_CASCADING)
|| inst->isPositioning(LLFloaterEnums::POSITIONING_CASCADE_GROUP)))
{
if (candidate_rect.mTop > inst->getRect().mTop)
{
candidate_floater = inst;
candidate_rect = inst->getRect();
}
}
}
}
return candidate_floater;
}
//static
LLFloater* LLFloaterReg::findInstance(std::string_view name, const LLSD& key)
{
LLFloater* res = NULL;
auto it = sGroupMap.find(name);
if (it != sGroupMap.end())
{
const std::string& groupname = it->second;
if (!groupname.empty())
{
instance_list_t& list = sInstanceMap[groupname];
for (LLFloater* inst : list)
{
if (inst->matchesKey(key))
{
res = inst;
break;
}
}
}
}
return res;
}
//static
LLFloater* LLFloaterReg::getInstance(std::string_view name, const LLSD& key)
{
LLFloater* res = findInstance(name, key);
if (!res)
{
auto it = sBuildMap.find(name);
if (it != sBuildMap.end())
{
const LLFloaterBuildFunc& build_func = it->second.mFunc;
const std::string& xui_file = it->second.mFile;
if (build_func)
{
auto it = sGroupMap.find(name);
if (it != sGroupMap.end())
{
const std::string& groupname = it->second;
if (!groupname.empty())
{
instance_list_t& list = sInstanceMap[groupname];
res = build_func(key);
if (!res)
{
LL_WARNS() << "Failed to build floater type: '" << name << "'." << LL_ENDL;
return NULL;
}
bool success = res->buildFromFile(xui_file);
if (!success)
{
LL_WARNS() << "Failed to build floater type: '" << name << "'." << LL_ENDL;
return NULL;
}
// Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe
if (res->mKey.isUndefined())
{
res->mKey = key;
}
res->setInstanceName(std::string(name));
LLFloater* last_floater = (list.empty() ? NULL : list.back());
res->applyControlsAndPosition(last_floater);
gFloaterView->adjustToFitScreen(res, false);
list.push_back(res);
}
}
}
}
if (!res)
{
LL_WARNS() << "Floater type: '" << name << "' not registered." << LL_ENDL;
}
}
return res;
}
//static
LLFloater* LLFloaterReg::removeInstance(std::string_view name, const LLSD& key)
{
LLFloater* res = NULL;
auto it = sGroupMap.find(name);
if (it != sGroupMap.end())
{
const std::string& groupname = it->second;
if (!groupname.empty())
{
instance_list_t& list = sInstanceMap[groupname];
for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
{
LLFloater* inst = *iter;
if (inst->matchesKey(key))
{
res = inst;
list.erase(iter);
break;
}
}
}
}
return res;
}
//static
// returns true if the instance existed
bool LLFloaterReg::destroyInstance(std::string_view name, const LLSD& key)
{
LLFloater* inst = removeInstance(name, key);
if (inst)
{
delete inst;
return true;
}
else
{
return false;
}
}
// Iterators
//static
LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(std::string_view name)
{
instance_map_t::iterator iter = sInstanceMap.find(name);
if (iter != sInstanceMap.end())
{
return iter->second;
}
else
{
return sNullInstanceList;
}
}
// Visibility Management
// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
//static
bool LLFloaterReg::canShowInstance(std::string_view name, const LLSD& key)
{
return mValidateSignal(name, key);
}
// [/RLVa:KB]
//static
LLFloater* LLFloaterReg::showInstance(std::string_view name, const LLSD& key, bool focus)
{
// if( sBlockShowFloaters
// // see EXT-7090
// && sAlwaysShowableList.find(name) == sAlwaysShowableList.end())
// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a
if ( (sBlockShowFloaters && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) || (!mValidateSignal(name, key)) )
// [/RLVa:KB]
return 0;//
LLFloater* instance = getInstance(name, key);
if (instance)
{
LL_INFOS() << "show instance for refreshing group ID: " << key.asString() << LL_ENDL;
instance->openFloater(key);
if (focus)
instance->setFocus(true);
}
return instance;
}
//static
// returns true if the instance exists
bool LLFloaterReg::hideInstance(std::string_view name, const LLSD& key)
{
LLFloater* instance = findInstance(name, key);
if (instance)
{
instance->closeHostedFloater();
}
return (instance != NULL);
}
//static
// returns true if the instance is visible when completed
bool LLFloaterReg::toggleInstance(std::string_view name, const LLSD& key)
{
LLFloater* instance = findInstance(name, key);
if (instance && instance->isShown())
{
instance->closeHostedFloater();
return false;
}
instance = showInstance(name, key, true);
return instance != nullptr;
}
//static
// returns true if the instance exists and is visible (doesnt matter minimized or not)
bool LLFloaterReg::instanceVisible(std::string_view name, const LLSD& key)
{
LLFloater* instance = findInstance(name, key);
return LLFloater::isVisible(instance);
}
//static
void LLFloaterReg::showInitialVisibleInstances()
{
// Iterate through alll registered instance names and show any with a save visible state
for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter)
{
const std::string& name = iter->first;
std::string controlname = getVisibilityControlName(name);
if (LLFloater::getControlGroup()->controlExists(controlname))
{
bool isvis = LLFloater::getControlGroup()->getBOOL(controlname);
if (isvis)
{
// <FS:Ansariel> Set correct window transparency at login
//showInstance(name, LLSD()); // keyed floaters shouldn't set save_vis to true
LLFloater* floater = showInstance(name, LLSD());
floater->updateTransparency(LLUICtrl::TT_INACTIVE);
// </FS:Ansariel>
}
}
}
}
//static
void LLFloaterReg::hideVisibleInstances(const std::set<std::string>& exceptions)
{
// Iterate through alll active instances and hide them
for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter)
{
const std::string& name = iter->first;
if (exceptions.find(name) != exceptions.end())
continue;
instance_list_t& list = iter->second;
for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
{
LLFloater* floater = *iter;
floater->pushVisible(false);
}
}
}
//static
void LLFloaterReg::restoreVisibleInstances()
{
// Iterate through all active instances and restore visibility
for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter)
{
instance_list_t& list = iter->second;
for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
{
LLFloater* floater = *iter;
floater->popVisible();
}
}
}
//static
std::string LLFloaterReg::getRectControlName(const std::string& name)
{
return std::string("floater_rect_") + getBaseControlName(name);
}
//static
std::string LLFloaterReg::declareRectControl(const std::string& name)
{
std::string controlname = getRectControlName(name);
LLFloater::getControlGroup()->declareRect(controlname, LLRect(),
llformat("Window Size for %s", name.c_str()),
LLControlVariable::PERSIST_NONDFT);
return controlname;
}
std::string LLFloaterReg::declarePosXControl(const std::string& name)
{
std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_x";
LLFloater::getControlGroup()->declareF32(controlname,
10.f,
llformat("Window X Position for %s", name.c_str()),
LLControlVariable::PERSIST_NONDFT);
return controlname;
}
std::string LLFloaterReg::declarePosYControl(const std::string& name)
{
std::string controlname = std::string("floater_pos_") + getBaseControlName(name) + "_y";
LLFloater::getControlGroup()->declareF32(controlname,
10.f,
llformat("Window Y Position for %s", name.c_str()),
LLControlVariable::PERSIST_NONDFT);
return controlname;
}
//static
std::string LLFloaterReg::getVisibilityControlName(const std::string& name)
{
return std::string("floater_vis_") + getBaseControlName(name);
}
//static
std::string LLFloaterReg::getBaseControlName(const std::string& name)
{
std::string res(name);
LLStringUtil::replaceChar( res, ' ', '_' );
return res;
}
//static
std::string LLFloaterReg::declareVisibilityControl(const std::string& name)
{
std::string controlname = getVisibilityControlName(name);
LLFloater::getControlGroup()->declareBOOL(controlname, false,
llformat("Window Visibility for %s", name.c_str()),
LLControlVariable::PERSIST_NONDFT);
return controlname;
}
//static
std::string LLFloaterReg::declareDockStateControl(const std::string& name)
{
std::string controlname = getDockStateControlName(name);
LLFloater::getControlGroup()->declareBOOL(controlname, true,
llformat("Window Docking state for %s", name.c_str()),
LLControlVariable::PERSIST_NONDFT);
return controlname;
}
//static
std::string LLFloaterReg::getDockStateControlName(const std::string& name)
{
std::string res = std::string("floater_dock_") + name;
LLStringUtil::replaceChar( res, ' ', '_' );
return res;
}
//static
void LLFloaterReg::registerControlVariables()
{
// Iterate through alll registered instance names and register rect and visibility control variables
for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter)
{
const std::string& name = iter->first;
// <FS:Zi> Save rects even when the floater wasn't opened this session
// if (LLFloater::getControlGroup()->controlExists(getRectControlName(name)))
// </FS:Zi>
if (!LLFloater::getControlGroup()->controlExists(getRectControlName(name)))
{
declareRectControl(name);
}
// <FS:Zi> Save rects even when the floater wasn't opened this session
// if (LLFloater::getControlGroup()->controlExists(getVisibilityControlName(name)))
// </FS:Zi>
if (!LLFloater::getControlGroup()->controlExists(getVisibilityControlName(name)))
{
declareVisibilityControl(name);
}
}
const LLSD& exclude_list = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("always_showable_floaters");
for (LLSD::array_const_iterator iter = exclude_list.beginArray();
iter != exclude_list.endArray();
iter++)
{
sAlwaysShowableList.insert(iter->asString());
}
}
//static
void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key)
{
//
// Floaters controlled by the toolbar behave a bit differently from others.
// Namely they have 3-4 states as defined in the design wiki page here:
// https://wiki.lindenlab.com/wiki/FUI_Button_states
//
// The basic idea is this:
// * If the target floater is minimized, this button press will un-minimize it.
// * Else if the target floater is closed open it.
// * Else if the target floater does not have focus, give it focus.
// * Also, if it is not on top, bring it forward when focus is given.
// * Else the target floater is open, close it.
//
std::string name = sdname.asString();
LLFloater* instance = getInstance(name, key);
if (!instance)
{
LL_DEBUGS() << "Unable to get instance of floater '" << name << "'" << LL_ENDL;
return;
}
// If hosted, we need to take that into account
LLFloater* host = instance->getHost();
if (host)
{
//FS:LO from above: * Else if the target floater does not have focus, give it focus. * Also, if it is not on top, bring it forward when focus is given.
//if (host->isMinimized() || !host->isShown() || !host->isFrontmost())
if (host->isMinimized() || !host->isShown() || (!host->hasFocus() || !host->isFrontmost()))
{
host->setMinimized(false);
instance->openFloater(key);
instance->setVisibleAndFrontmost(true, key);
}
else if (!instance->getVisible())
{
instance->openFloater(key);
instance->setVisibleAndFrontmost(true, key);
instance->setFocus(true);
}
else
{
instance->closeHostedFloater();
}
}
else
{
if (instance->isMinimized())
{
instance->setMinimized(false);
instance->setVisibleAndFrontmost(true, key);
}
else if (!instance->isShown())
{
instance->openFloater(key);
instance->setVisibleAndFrontmost(true, key);
}
//FS:LO from above: * Else if the target floater does not have focus, give it focus. * Also, if it is not on top, bring it forward when focus is given.
//else if (!instance->isFrontmost())
else if (!instance->hasFocus() || !instance->isFrontmost())
{
instance->setVisibleAndFrontmost(true, key);
}
else
{
instance->closeHostedFloater();
}
}
}
// static
// Same as toggleInstanceOrBringToFront but does not close floater.
// unlike showInstance() does not trigger onOpen() if already open
void LLFloaterReg::showInstanceOrBringToFront(const LLSD& sdname, const LLSD& key)
{
std::string name = sdname.asString();
LLFloater* instance = getInstance(name, key);
if (!instance)
{
LL_DEBUGS() << "Unable to get instance of floater '" << name << "'" << LL_ENDL;
return;
}
// If hosted, we need to take that into account
LLFloater* host = instance->getHost();
if (host)
{
if (host->isMinimized() || !host->isShown() || !host->isFrontmost())
{
host->setMinimized(false);
instance->openFloater(key);
instance->setVisibleAndFrontmost(true, key);
}
else if (!instance->getVisible())
{
instance->openFloater(key);
instance->setVisibleAndFrontmost(true, key);
instance->setFocus(true);
}
}
else
{
if (instance->isMinimized())
{
instance->setMinimized(false);
instance->setVisibleAndFrontmost(true, key);
}
else if (!instance->isShown())
{
instance->openFloater(key);
instance->setVisibleAndFrontmost(true, key);
}
else if (!instance->isFrontmost())
{
instance->setVisibleAndFrontmost(true, key);
}
}
}
// static
U32 LLFloaterReg::getVisibleFloaterInstanceCount()
{
U32 count = 0;
std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
for( ; it != it_end; ++it)
{
const std::string& group_name = it->second;
instance_list_t& instances = sInstanceMap[group_name];
for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
{
LLFloater* inst = *iter;
if (inst->getVisible() && !inst->isMinimized())
{
count++;
}
}
}
return count;
}
+193
View File
@@ -0,0 +1,193 @@
/**
* @file llfloaterreg.h
* @brief LLFloaterReg Floater Registration Class
*
* $LicenseInfo:firstyear=2002&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 LLFLOATERREG_H
#define LLFLOATERREG_H
/// llcommon
#include "llrect.h"
#include "llsd.h"
#include <list>
#include <boost/function.hpp>
// [RLVa:KB] - Checked: 2011-05-25 (RLVa-1.4.0a)
#include <boost/signals2.hpp>
#include "llboost.h"
// [/RLVa:KB]
//*******************************************************
//
// Floater Class Registry
//
class LLFloater;
class LLUICtrl;
typedef boost::function<LLFloater* (const LLSD& key)> LLFloaterBuildFunc;
// [SL:KB] - Patch: UI-Base | Checked: 2010-12-01 (Catznip-3.0.0a) | Added: Catznip-2.4.0g
typedef boost::function<const std::string& (void)> LLFloaterFileFunc;
// [/SL:KB]
class LLFloaterReg
{
public:
// We use a list of LLFloater's instead of a set for two reasons:
// 1) With a list we have a predictable ordering, useful for finding the last opened floater of a given type.
// 2) We can change the key of a floater without altering the list.
typedef std::list<LLFloater*> instance_list_t;
typedef const instance_list_t const_instance_list_t;
typedef std::map<std::string, instance_list_t, std::less<>> instance_map_t;
struct BuildData
{
LLFloaterBuildFunc mFunc;
// [SL:KB] - Patch: UI-Base | Checked: 2010-12-01 (Catznip-3.0.0a) | Added: Catznip-2.4.0g
LLFloaterFileFunc mFileFunc;
// [/SL:KB]
std::string mFile;
};
typedef std::map<std::string, BuildData, std::less<>> build_map_t;
private:
friend class LLFloaterRegListener;
static instance_list_t sNullInstanceList;
static instance_map_t sInstanceMap;
static build_map_t sBuildMap;
static std::map<std::string, std::string, std::less<>> sGroupMap;
static bool sBlockShowFloaters;
/**
* Defines list of floater names that can be shown despite state of sBlockShowFloaters.
*/
static std::set<std::string, std::less<>> sAlwaysShowableList;
// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a
// Used to determine whether a floater can be shown
public:
typedef boost::signals2::signal<bool(std::string_view, const LLSD&), boost_boolean_combiner> validate_signal_t;
static boost::signals2::connection setValidateCallback(const validate_signal_t::slot_type& cb) { return mValidateSignal.connect(cb); }
private:
static validate_signal_t mValidateSignal;
// [/RLVa:KB]
public:
// Registration
// usage: LLFloaterClassRegistry::add("foo", (LLFloaterBuildFunc)&LLFloaterClassRegistry::build<LLFloaterFoo>);
template <class T>
static LLFloater* build(const LLSD& key)
{
T* floater = new T(key);
return floater;
}
static void add(const std::string& name, const std::string& file, const LLFloaterBuildFunc& func,
const std::string& groupname = LLStringUtil::null);
static bool isRegistered(std::string_view name);
// Helpers
static LLFloater* getLastFloaterInGroup(std::string_view name);
static LLFloater* getLastFloaterCascading();
static instance_list_t getAllFloatersInGroup(LLFloater* floater); // <FS:Ansariel> FIRE-24125: Add option to close all floaters of a group
// Find / get (create) / remove / destroy
static LLFloater* findInstance(std::string_view name, const LLSD& key = LLSD());
static LLFloater* getInstance(std::string_view name, const LLSD& key = LLSD());
static LLFloater* removeInstance(std::string_view name, const LLSD& key = LLSD());
static bool destroyInstance(std::string_view name, const LLSD& key = LLSD());
// Iterators
// <FS> ignore dangling reference false positives in gcc13
#if defined(__GNUC__) && (__GNUC__ >= 13)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdangling-reference"
#endif
// </FS>
static const_instance_list_t& getFloaterList(std::string_view name);
// <FS> ignore dangling reference false positives in gcc13
#if defined(__GNUC__) && (__GNUC__ >= 13)
#pragma GCC diagnostic pop
#endif
// </FS>
// Visibility Management
// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
// return false if floater can not be shown (=doesn't pass the validation filter)
static bool canShowInstance(std::string_view name, const LLSD& key = LLSD());
// [/RLVa:KB]
// return NULL if instance not found or can't create instance (no builder)
static LLFloater* showInstance(std::string_view name, const LLSD& key = LLSD(), bool focus = false);
// Close a floater (may destroy or set invisible)
// return false if can't find instance
static bool hideInstance(std::string_view name, const LLSD& key = LLSD());
// return true if instance is visible:
static bool toggleInstance(std::string_view name, const LLSD& key = LLSD());
static bool instanceVisible(std::string_view name, const LLSD& key = LLSD());
static void showInitialVisibleInstances();
static void hideVisibleInstances(const std::set<std::string>& exceptions = std::set<std::string>());
static void restoreVisibleInstances();
// Control Variables
static std::string getRectControlName(const std::string& name);
static std::string declareRectControl(const std::string& name);
static std::string declarePosXControl(const std::string& name);
static std::string declarePosYControl(const std::string& name);
static std::string getVisibilityControlName(const std::string& name);
static std::string declareVisibilityControl(const std::string& name);
static std::string getBaseControlName(const std::string& name);
static std::string declareDockStateControl(const std::string& name);
static std::string getDockStateControlName(const std::string& name);
static void registerControlVariables();
// Callback wrappers
static void toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD());
static void showInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD());
// Typed find / get / show
template <class T>
static T* findTypedInstance(std::string_view name, const LLSD& key = LLSD())
{
return dynamic_cast<T*>(findInstance(name, key));
}
template <class T>
static T* getTypedInstance(std::string_view name, const LLSD& key = LLSD())
{
return dynamic_cast<T*>(getInstance(name, key));
}
template <class T>
static T* showTypedInstance(std::string_view name, const LLSD& key = LLSD(), bool focus = false)
{
return dynamic_cast<T*>(showInstance(name, key, focus));
}
static void blockShowFloaters(bool value) { sBlockShowFloaters = value;}
static U32 getVisibleFloaterInstanceCount();
};
#endif
+156
View File
@@ -0,0 +1,156 @@
/**
* @file llfloaterreglistener.cpp
* @author Nat Goodspeed
* @date 2009-08-12
* @brief Implementation for llfloaterreglistener.
*
* $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$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "llfloaterreglistener.h"
// STL headers
// std headers
// external library headers
// other Linden headers
#include "llfloaterreg.h"
#include "llfloater.h"
#include "llbutton.h"
LLFloaterRegListener::LLFloaterRegListener():
LLEventAPI("LLFloaterReg",
"LLFloaterReg listener to (e.g.) show/hide LLFloater instances")
{
add("getBuildMap",
"Return on [\"reply\"] data about all registered LLFloaterReg floater names",
&LLFloaterRegListener::getBuildMap,
LLSD().with("reply", LLSD()));
LLSD requiredName;
requiredName["name"] = LLSD();
add("showInstance",
"Ask to display the floater specified in [\"name\"]",
&LLFloaterRegListener::showInstance,
requiredName);
add("hideInstance",
"Ask to hide the floater specified in [\"name\"]",
&LLFloaterRegListener::hideInstance,
requiredName);
add("toggleInstance",
"Ask to toggle the state of the floater specified in [\"name\"]",
&LLFloaterRegListener::toggleInstance,
requiredName);
add("instanceVisible",
"Return on [\"reply\"] an event whose [\"visible\"] indicates the visibility "
"of the floater specified in [\"name\"]",
&LLFloaterRegListener::instanceVisible,
requiredName);
LLSD requiredNameButton;
requiredNameButton["name"] = LLSD();
requiredNameButton["button"] = LLSD();
add("clickButton",
"Simulate clicking the named [\"button\"] in the visible floater named in [\"name\"]",
&LLFloaterRegListener::clickButton,
requiredNameButton);
}
void LLFloaterRegListener::getBuildMap(const LLSD& event) const
{
LLSD reply;
// Build an LLSD map that mirrors sBuildMap. Since we have no good way to
// represent a C++ callable in LLSD, the only part of BuildData we can
// store is the filename. For each LLSD map entry, it would be more
// extensible to store a nested LLSD map containing a single key "file" --
// but we don't bother, simply storing the string filename instead.
for (LLFloaterReg::build_map_t::const_iterator mi(LLFloaterReg::sBuildMap.begin()),
mend(LLFloaterReg::sBuildMap.end());
mi != mend; ++mi)
{
reply[mi->first] = mi->second.mFile;
}
// Send the reply to the LLEventPump named in event["reply"].
sendReply(reply, event);
}
void LLFloaterRegListener::showInstance(const LLSD& event) const
{
LLFloaterReg::showInstance(event["name"].asString(), event["key"], event["focus"]);
}
void LLFloaterRegListener::hideInstance(const LLSD& event) const
{
LLFloaterReg::hideInstance(event["name"].asString(), event["key"]);
}
void LLFloaterRegListener::toggleInstance(const LLSD& event) const
{
LLFloaterReg::toggleInstance(event["name"].asString(), event["key"]);
}
void LLFloaterRegListener::instanceVisible(const LLSD& event) const
{
sendReply(LLSDMap("visible", LLFloaterReg::instanceVisible(event["name"].asString(), event["key"])),
event);
}
void LLFloaterRegListener::clickButton(const LLSD& event) const
{
// If the caller requests a reply, build the reply.
LLReqID reqID(event);
LLSD reply(reqID.makeResponse());
LLFloater* floater = LLFloaterReg::findInstance(event["name"].asString(), event["key"]);
if (! LLFloater::isShown(floater))
{
reply["type"] = "LLFloater";
reply["name"] = event["name"];
reply["key"] = event["key"];
reply["error"] = floater? "!isShown()" : "NULL";
}
else
{
// Here 'floater' points to an LLFloater instance with the specified
// name and key which isShown().
LLButton* button = floater->findChild<LLButton>(event["button"].asString());
if (! LLButton::isAvailable(button))
{
reply["type"] = "LLButton";
reply["name"] = event["button"];
reply["error"] = button? "!isAvailable()" : "NULL";
}
else
{
// Here 'button' points to an isAvailable() LLButton child of
// 'floater' with the specified button name. Pretend to click it.
button->onCommit();
// Leave reply["error"] isUndefined(): no error, i.e. success.
}
}
// Send a reply only if caller asked for a reply.
LLSD replyPump(event["reply"]);
if (replyPump.isString()) // isUndefined() if absent
{
LLEventPumps::instance().obtain(replyPump).post(reply);
}
}
+54
View File
@@ -0,0 +1,54 @@
/**
* @file llfloaterreglistener.h
* @author Nat Goodspeed
* @date 2009-08-12
* @brief Wrap (subset of) LLFloaterReg API with an event API
*
* $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$
*/
#if ! defined(LL_LLFLOATERREGLISTENER_H)
#define LL_LLFLOATERREGLISTENER_H
#include "lleventapi.h"
#include <string>
class LLSD;
/// Event API wrapper for LLFloaterReg
class LLFloaterRegListener: public LLEventAPI
{
public:
/// As all public LLFloaterReg methods are static, there's no point in
/// binding an LLFloaterReg instance.
LLFloaterRegListener();
private:
void getBuildMap(const LLSD& event) const;
void showInstance(const LLSD& event) const;
void hideInstance(const LLSD& event) const;
void toggleInstance(const LLSD& event) const;
void instanceVisible(const LLSD& event) const;
void clickButton(const LLSD& event) const;
};
#endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */
+77
View File
@@ -0,0 +1,77 @@
/**
* @file llflyoutbutton.cpp
* @brief LLFlyoutButton base class
*
* $LicenseInfo:firstyear=2001&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$
*/
#include "linden_common.h"
// file includes
#include "llflyoutbutton.h"
//static LLDefaultChildRegistry::Register<LLFlyoutButton> r2("flyout_button");
const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24;
LLFlyoutButton::LLFlyoutButton(const Params& p)
: LLComboBox(p),
mToggleState(false),
mActionButton(NULL)
{
// Always use text box
// Text label button
LLButton::Params bp(p.action_button);
bp.name(p.label);
bp.label(p.label);
bp.rect.left(0).bottom(0).width(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH).height(getRect().getHeight());
bp.click_callback.function(boost::bind(&LLFlyoutButton::onActionButtonClick, this, _2));
bp.follows.flags(FOLLOWS_ALL);
mActionButton = LLUICtrlFactory::create<LLButton>(bp);
addChild(mActionButton);
}
void LLFlyoutButton::onActionButtonClick(const LLSD& data)
{
// remember last list selection?
mList->deselect();
onCommit();
}
void LLFlyoutButton::draw()
{
mActionButton->setToggleState(mToggleState);
mButton->setToggleState(mToggleState);
//FIXME: this should be an attribute of comboboxes, whether they have a distinct label or
// the label reflects the last selected item, for now we have to manually remove the label
setLabel(LLStringUtil::null);
LLComboBox::draw();
}
void LLFlyoutButton::setToggleState(bool state)
{
mToggleState = state;
}
+68
View File
@@ -0,0 +1,68 @@
/**
* @file llflyoutbutton.h
* @brief LLFlyoutButton base class
*
* $LicenseInfo:firstyear=2001&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$
*/
// A control that displays the name of the chosen item, which when clicked
// shows a scrolling box of choices.
#ifndef LL_LLFLYOUTBUTTON_H
#define LL_LLFLYOUTBUTTON_H
#include "llcombobox.h"
// Classes
class LLFlyoutButton : public LLComboBox
{
public:
struct Params : public LLInitParam::Block<Params, LLComboBox::Params>
{
Optional<LLButton::Params> action_button;
Deprecated allow_text_entry;
Params()
: action_button("action_button"),
allow_text_entry("allow_text_entry")
{
changeDefault(LLComboBox::Params::allow_text_entry, false);
}
};
protected:
LLFlyoutButton(const Params&);
friend class LLUICtrlFactory;
public:
virtual void draw();
void setToggleState(bool state);
void onActionButtonClick(const LLSD& data);
protected:
LLButton* mActionButton;
bool mToggleState;
};
#endif // LL_LLFLYOUTBUTTON_H
+519
View File
@@ -0,0 +1,519 @@
/**
* @file llfocusmgr.cpp
* @brief LLFocusMgr base class
*
* $LicenseInfo:firstyear=2002&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$
*/
#include "linden_common.h"
#include "llfocusmgr.h"
#include "lluictrl.h"
#include "v4color.h"
const F32 FOCUS_FADE_TIME = 0.3f;
LLFocusableElement::LLFocusableElement()
: mFocusLostCallback(NULL),
mFocusReceivedCallback(NULL),
mFocusChangedCallback(NULL),
mTopLostCallback(NULL)
{
}
// virtual
bool LLFocusableElement::handleKey(KEY key, MASK mask, bool called_from_parent)
{
return false;
}
// virtual
bool LLFocusableElement::handleKeyUp(KEY key, MASK mask, bool called_from_parent)
{
return false;
}
// virtual
bool LLFocusableElement::handleUnicodeChar(llwchar uni_char, bool called_from_parent)
{
return false;
}
// virtual
bool LLFocusableElement::wantsKeyUpKeyDown() const
{
return false;
}
//virtual
bool LLFocusableElement::wantsReturnKey() const
{
return false;
}
// virtual
LLFocusableElement::~LLFocusableElement()
{
auto free_signal = [&](focus_signal_t*& signal)
{
if (signal)
{
signal->disconnect_all_slots();
delete signal;
signal = nullptr;
}
};
free_signal(mFocusLostCallback);
free_signal(mFocusReceivedCallback);
free_signal(mFocusChangedCallback);
free_signal(mTopLostCallback);
}
void LLFocusableElement::onFocusReceived()
{
if (mFocusReceivedCallback) (*mFocusReceivedCallback)(this);
if (mFocusChangedCallback) (*mFocusChangedCallback)(this);
}
void LLFocusableElement::onFocusLost()
{
if (mFocusLostCallback) (*mFocusLostCallback)(this);
if (mFocusChangedCallback) (*mFocusChangedCallback)(this);
}
void LLFocusableElement::onTopLost()
{
if (mTopLostCallback) (*mTopLostCallback)(this);
}
bool LLFocusableElement::hasFocus() const
{
return gFocusMgr.getKeyboardFocus() == this;
}
void LLFocusableElement::setFocus(bool b)
{
}
boost::signals2::connection LLFocusableElement::setFocusLostCallback( const focus_signal_t::slot_type& cb)
{
if (!mFocusLostCallback) mFocusLostCallback = new focus_signal_t();
return mFocusLostCallback->connect(cb);
}
boost::signals2::connection LLFocusableElement::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)
{
if (!mFocusReceivedCallback) mFocusReceivedCallback = new focus_signal_t();
return mFocusReceivedCallback->connect(cb);
}
boost::signals2::connection LLFocusableElement::setFocusChangedCallback(const focus_signal_t::slot_type& cb)
{
if (!mFocusChangedCallback) mFocusChangedCallback = new focus_signal_t();
return mFocusChangedCallback->connect(cb);
}
boost::signals2::connection LLFocusableElement::setTopLostCallback(const focus_signal_t::slot_type& cb)
{
if (!mTopLostCallback) mTopLostCallback = new focus_signal_t();
return mTopLostCallback->connect(cb);
}
typedef std::list<LLHandle<LLView> > view_handle_list_t;
typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t;
struct LLFocusMgr::Impl
{
// caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost
view_handle_list_t mCachedKeyboardFocusList;
focus_history_map_t mFocusHistory;
};
LLFocusMgr gFocusMgr;
LLFocusMgr::LLFocusMgr()
: mLockedView( NULL ),
mMouseCaptor( NULL ),
mKeyboardFocus( NULL ),
mLastKeyboardFocus( NULL ),
mDefaultKeyboardFocus( NULL ),
mKeystrokesOnly(false),
mTopCtrl( NULL ),
mAppHasFocus(true), // Macs don't seem to notify us that we've gotten focus, so default to true
mImpl(new LLFocusMgr::Impl)
{
}
LLFocusMgr::~LLFocusMgr()
{
mImpl->mFocusHistory.clear();
delete mImpl;
mImpl = NULL;
}
void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
{
if( childHasMouseCapture( view ) )
{
setMouseCapture( NULL );
}
if( childHasKeyboardFocus( view ))
{
if (view == mLockedView)
{
mLockedView = NULL;
setKeyboardFocus( NULL );
}
else
{
setKeyboardFocus( mLockedView );
}
}
if(LLUI::instanceExists()) LLUI::getInstance()->removePopup(view);
}
void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, bool lock, bool keystrokes_only)
{
// notes if keyboard focus is changed again (by onFocusLost/onFocusReceived)
// making the rest of our processing unnecessary since it will already be
// handled by the recursive call
static bool focus_dirty;
focus_dirty = false;
if (mLockedView &&
(new_focus == NULL ||
(new_focus != mLockedView
&& dynamic_cast<LLView*>(new_focus)
&& !dynamic_cast<LLView*>(new_focus)->hasAncestor(mLockedView))))
{
// don't allow focus to go to anything that is not the locked focus
// or one of its descendants
return;
}
mKeystrokesOnly = keystrokes_only;
if( new_focus != mKeyboardFocus )
{
mLastKeyboardFocus = mKeyboardFocus;
mKeyboardFocus = new_focus;
// list of the focus and it's ancestors
view_handle_list_t old_focus_list = mImpl->mCachedKeyboardFocusList;
view_handle_list_t new_focus_list;
// walk up the tree to root and add all views to the new_focus_list
for (LLView* ctrl = dynamic_cast<LLView*>(mKeyboardFocus); ctrl; ctrl = ctrl->getParent())
{
new_focus_list.push_back(ctrl->getHandle());
}
// remove all common ancestors since their focus is unchanged
while (!new_focus_list.empty() &&
!old_focus_list.empty() &&
new_focus_list.back() == old_focus_list.back())
{
new_focus_list.pop_back();
old_focus_list.pop_back();
}
// walk up the old focus branch calling onFocusLost
// we bubble up the tree to release focus, and back down to add
for (view_handle_list_t::iterator old_focus_iter = old_focus_list.begin();
old_focus_iter != old_focus_list.end() && !focus_dirty;
old_focus_iter++)
{
LLView* old_focus_view = old_focus_iter->get();
if (old_focus_view)
{
mImpl->mCachedKeyboardFocusList.pop_front();
old_focus_view->onFocusLost();
}
}
// walk down the new focus branch calling onFocusReceived
for (view_handle_list_t::reverse_iterator new_focus_riter = new_focus_list.rbegin();
new_focus_riter != new_focus_list.rend() && !focus_dirty;
new_focus_riter++)
{
LLView* new_focus_view = new_focus_riter->get();
if (new_focus_view)
{
mImpl->mCachedKeyboardFocusList.push_front(new_focus_view->getHandle());
new_focus_view->onFocusReceived();
}
}
// if focus was changed as part of an onFocusLost or onFocusReceived call
// stop iterating on current list since it is now invalid
if (focus_dirty)
{
return;
}
// If we've got a default keyboard focus, and the caller is
// releasing keyboard focus, move to the default.
if (mDefaultKeyboardFocus != NULL && mKeyboardFocus == NULL)
{
mDefaultKeyboardFocus->setFocus(true);
}
LLView* focus_subtree = dynamic_cast<LLView*>(mKeyboardFocus);
LLView* viewp = dynamic_cast<LLView*>(mKeyboardFocus);
// find root-most focus root
while(viewp)
{
if (viewp->isFocusRoot())
{
focus_subtree = viewp;
}
viewp = viewp->getParent();
}
if (focus_subtree)
{
LLView* focused_view = dynamic_cast<LLView*>(mKeyboardFocus);
mImpl->mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>();
}
}
if (lock)
{
lockFocus();
}
focus_dirty = true;
}
// Returns true is parent or any descedent of parent has keyboard focus.
bool LLFocusMgr::childHasKeyboardFocus(const LLView* parent ) const
{
LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus);
while( focus_view )
{
if( focus_view == parent )
{
return true;
}
focus_view = focus_view->getParent();
}
return false;
}
// Returns true is parent or any descedent of parent is the mouse captor.
bool LLFocusMgr::childHasMouseCapture( const LLView* parent ) const
{
if( mMouseCaptor && dynamic_cast<LLView*>(mMouseCaptor) != NULL )
{
LLView* captor_view = (LLView*)mMouseCaptor;
while( captor_view )
{
if( captor_view == parent )
{
return true;
}
captor_view = captor_view->getParent();
}
}
return false;
}
void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus )
{
// should be ok to unlock here, as you have to know the locked view
// in order to unlock it
if (focus == mLockedView)
{
mLockedView = NULL;
}
if( mKeyboardFocus == focus )
{
mKeyboardFocus = NULL;
}
}
bool LLFocusMgr::keyboardFocusHasAccelerators() const
{
LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus);
while( focus_view )
{
if(focus_view->hasAccelerators())
{
return true;
}
focus_view = focus_view->getParent();
}
return false;
}
void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )
{
if( new_captor != mMouseCaptor )
{
LLMouseHandler* old_captor = mMouseCaptor;
mMouseCaptor = new_captor;
if (LLView::sDebugMouseHandling)
{
if (new_captor)
{
LL_INFOS() << "New mouse captor: " << new_captor->getName() << LL_ENDL;
}
else
{
LL_INFOS() << "New mouse captor: NULL" << LL_ENDL;
}
}
if( old_captor )
{
old_captor->onMouseCaptureLost();
}
}
}
void LLFocusMgr::removeMouseCaptureWithoutCallback( const LLMouseHandler* captor )
{
if( mMouseCaptor == captor )
{
mMouseCaptor = NULL;
}
}
bool LLFocusMgr::childIsTopCtrl( const LLView* parent ) const
{
LLView* top_view = (LLView*)mTopCtrl;
while( top_view )
{
if( top_view == parent )
{
return true;
}
top_view = top_view->getParent();
}
return false;
}
// set new_top = NULL to release top_view.
void LLFocusMgr::setTopCtrl( LLUICtrl* new_top )
{
LLUICtrl* old_top = mTopCtrl;
if( new_top != old_top )
{
mTopCtrl = new_top;
if (old_top)
{
old_top->onTopLost();
}
}
}
void LLFocusMgr::removeTopCtrlWithoutCallback( const LLUICtrl* top_view )
{
if( mTopCtrl == top_view )
{
mTopCtrl = NULL;
}
}
void LLFocusMgr::lockFocus()
{
mLockedView = dynamic_cast<LLUICtrl*>(mKeyboardFocus);
}
void LLFocusMgr::unlockFocus()
{
mLockedView = NULL;
}
F32 LLFocusMgr::getFocusFlashAmt() const
{
return clamp_rescale(mFocusFlashTimer.getElapsedTimeF32(), 0.f, FOCUS_FADE_TIME, 1.f, 0.f);
}
LLColor4 LLFocusMgr::getFocusColor() const
{
static LLUIColor focus_color_cached = LLUIColorTable::instance().getColor("FocusColor");
LLColor4 focus_color = lerp(focus_color_cached, LLColor4::white, getFocusFlashAmt());
// de-emphasize keyboard focus when app has lost focus (to avoid typing into wrong window problem)
if (!mAppHasFocus)
{
focus_color.mV[VALPHA] *= 0.4f;
}
return focus_color;
}
void LLFocusMgr::triggerFocusFlash()
{
mFocusFlashTimer.reset();
}
void LLFocusMgr::setAppHasFocus(bool focus)
{
if (!mAppHasFocus && focus)
{
triggerFocusFlash();
}
// release focus from "top ctrl"s, which generally hides them
if (!focus)
{
if(LLUI::instanceExists()) LLUI::getInstance()->clearPopups();
}
mAppHasFocus = focus;
}
LLView* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
{
if (subtree_root)
{
focus_history_map_t::const_iterator found_it = mImpl->mFocusHistory.find(subtree_root->getHandle());
if (found_it != mImpl->mFocusHistory.end())
{
// found last focus for this subtree
return found_it->second.get();
}
}
return NULL;
}
void LLFocusMgr::clearLastFocusForGroup(LLView* subtree_root)
{
if (subtree_root)
{
mImpl->mFocusHistory.erase(subtree_root->getHandle());
}
}
+160
View File
@@ -0,0 +1,160 @@
/**
* @file llfocusmgr.h
* @brief LLFocusMgr base class
*
* $LicenseInfo:firstyear=2002&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$
*/
// Singleton that manages keyboard and mouse focus
#ifndef LL_LLFOCUSMGR_H
#define LL_LLFOCUSMGR_H
#include "llstring.h"
#include "llframetimer.h"
#include "llui.h"
class LLUICtrl;
class LLMouseHandler;
class LLView;
// NOTE: the LLFocusableElement class declaration has been moved here from lluictrl.h.
class LLFocusableElement
{
friend class LLFocusMgr; // allow access to focus change handlers
public:
LLFocusableElement();
virtual ~LLFocusableElement();
virtual void setFocus( bool b );
virtual bool hasFocus() const;
typedef boost::signals2::signal<void(LLFocusableElement*)> focus_signal_t;
boost::signals2::connection setFocusLostCallback( const focus_signal_t::slot_type& cb);
boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb);
boost::signals2::connection setFocusChangedCallback(const focus_signal_t::slot_type& cb);
boost::signals2::connection setTopLostCallback(const focus_signal_t::slot_type& cb);
// These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus.
virtual bool handleKey(KEY key, MASK mask, bool called_from_parent);
virtual bool handleKeyUp(KEY key, MASK mask, bool called_from_parent);
virtual bool handleUnicodeChar(llwchar uni_char, bool called_from_parent);
/**
* If true this LLFocusableElement wants to receive KEYUP and KEYDOWN messages
* even for normal character strokes.
* Default implementation returns false.
*/
virtual bool wantsKeyUpKeyDown() const;
virtual bool wantsReturnKey() const;
virtual void onTopLost(); // called when registered as top ctrl and user clicks elsewhere
protected:
virtual void onFocusReceived();
virtual void onFocusLost();
focus_signal_t* mFocusLostCallback;
focus_signal_t* mFocusReceivedCallback;
focus_signal_t* mFocusChangedCallback;
focus_signal_t* mTopLostCallback;
};
class LLFocusMgr
{
public:
LLFocusMgr();
~LLFocusMgr();
// Mouse Captor
void setMouseCapture(LLMouseHandler* new_captor); // new_captor = NULL to release the mouse.
LLMouseHandler* getMouseCapture() const { return mMouseCaptor; }
void removeMouseCaptureWithoutCallback( const LLMouseHandler* captor );
bool childHasMouseCapture( const LLView* parent ) const;
// Keyboard Focus
void setKeyboardFocus(LLFocusableElement* new_focus, bool lock = false, bool keystrokes_only = false); // new_focus = NULL to release the focus.
LLFocusableElement* getKeyboardFocus() const { return mKeyboardFocus; }
LLFocusableElement* getLastKeyboardFocus() const { return mLastKeyboardFocus; }
bool childHasKeyboardFocus( const LLView* parent ) const;
void removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus );
bool getKeystrokesOnly() { return mKeystrokesOnly; }
void setKeystrokesOnly(bool keystrokes_only) { mKeystrokesOnly = keystrokes_only; }
F32 getFocusFlashAmt() const;
S32 getFocusFlashWidth() const { return ll_round(lerp(1.f, 3.f, getFocusFlashAmt())); }
LLColor4 getFocusColor() const;
void triggerFocusFlash();
bool getAppHasFocus() const { return mAppHasFocus; }
void setAppHasFocus(bool focus);
LLView* getLastFocusForGroup(LLView* subtree_root) const;
void clearLastFocusForGroup(LLView* subtree_root);
// If setKeyboardFocus(NULL) is called, and there is a non-NULL default
// keyboard focus view, focus goes there. JC
void setDefaultKeyboardFocus(LLFocusableElement* default_focus) { mDefaultKeyboardFocus = default_focus; }
LLFocusableElement* getDefaultKeyboardFocus() const { return mDefaultKeyboardFocus; }
// Top View
void setTopCtrl(LLUICtrl* new_top);
LLUICtrl* getTopCtrl() const { return mTopCtrl; }
void removeTopCtrlWithoutCallback( const LLUICtrl* top_view );
bool childIsTopCtrl( const LLView* parent ) const;
// All Three
void releaseFocusIfNeeded( LLView* top_view );
void lockFocus();
void unlockFocus();
bool focusLocked() const { return mLockedView != NULL; }
bool keyboardFocusHasAccelerators() const;
struct Impl;
private:
LLUICtrl* mLockedView;
// Mouse Captor
LLMouseHandler* mMouseCaptor; // Mouse events are premptively routed to this object
// Keyboard Focus
LLFocusableElement* mKeyboardFocus; // Keyboard events are preemptively routed to this object
LLFocusableElement* mLastKeyboardFocus; // who last had focus
LLFocusableElement* mDefaultKeyboardFocus;
bool mKeystrokesOnly;
// Top View
LLUICtrl* mTopCtrl;
LLFrameTimer mFocusFlashTimer;
bool mAppHasFocus;
Impl * mImpl;
};
extern LLFocusMgr gFocusMgr;
#endif // LL_LLFOCUSMGR_H
File diff suppressed because it is too large Load Diff
+459
View File
@@ -0,0 +1,459 @@
/**
* @file llfolderview.h
* @brief Definition of the folder view collection of classes.
*
* $LicenseInfo:firstyear=2001&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$
*/
/**
*
* The folder view collection of classes provides an interface for
* making a 'folder view' similar to the way the a single pane file
* folder interface works.
*
*/
#ifndef LL_LLFOLDERVIEW_H
#define LL_LLFOLDERVIEW_H
#include "llfolderviewitem.h" // because LLFolderView is-a LLFolderViewFolder
#include "lluictrl.h"
#include "v4color.h"
#include "lldepthstack.h"
#include "lleditmenuhandler.h"
#include "llfontgl.h"
#include "llscrollcontainer.h"
class LLFolderViewModelInterface;
class LLFolderViewGroupedItemModel;
class LLFolderViewFolder;
class LLFolderViewItem;
class LLFolderViewFilter;
class LLPanel;
class LLLineEditor;
class LLMenuGL;
class LLUICtrl;
class LLTextBox;
/**
* Class LLFolderViewScrollContainer
*
* A scroll container which provides the information about the height
* of currently displayed folder view contents.
* Used for updating vertical scroll bar visibility in inventory panel.
* See LLScrollContainer::calcVisibleSize().
*/
class LLFolderViewScrollContainer : public LLScrollContainer
{
public:
/*virtual*/ ~LLFolderViewScrollContainer() {};
/*virtual*/ const LLRect getScrolledViewRect() const;
protected:
LLFolderViewScrollContainer(const LLScrollContainer::Params& p);
friend class LLUICtrlFactory;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderView
//
// The LLFolderView represents the root level folder view object.
// It manages the screen region of the folder view.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
{
public:
struct Params : public LLInitParam::Block<Params, LLFolderViewFolder::Params>
{
Mandatory<LLPanel*> parent_panel;
Optional<std::string> title;
Optional<bool> use_label_suffix,
allow_multiselect,
allow_drag,
show_empty_message,
use_ellipses,
show_item_link_overlays,
suppress_folder_menu;
Mandatory<LLFolderViewModelInterface*> view_model;
Optional<LLFolderViewGroupedItemModel*> grouped_item_model;
Mandatory<std::string> options_menu;
Params();
};
friend class LLFolderViewScrollContainer;
typedef folder_view_item_deque selected_items_t;
LLFolderView(const Params&);
virtual ~LLFolderView( void );
virtual bool canFocusChildren() const;
virtual const LLFolderView* getRoot() const { return this; }
virtual LLFolderView* getRoot() { return this; }
LLFolderViewModelInterface* getFolderViewModel() { return mViewModel; }
const LLFolderViewModelInterface* getFolderViewModel() const { return mViewModel; }
LLFolderViewGroupedItemModel* getFolderViewGroupedItemModel() { return mGroupedItemModel; }
const LLFolderViewGroupedItemModel* getFolderViewGroupedItemModel() const { return mGroupedItemModel; }
typedef boost::signals2::signal<void (const std::deque<LLFolderViewItem*>& items, bool user_action)> signal_t;
void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); }
void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); }
bool getAllowMultiSelect() { return mAllowMultiSelect; }
bool getAllowDrag() { return mAllowDrag; }
void setSingleFolderMode(bool is_single_mode) { mSingleFolderMode = is_single_mode; }
bool isSingleFolderMode() { return mSingleFolderMode; }
// Close all folders in the view
void closeAllFolders();
void openTopLevelFolders();
virtual void addFolder( LLFolderViewFolder* folder);
// Find width and height of this object and its children. Also
// makes sure that this view and its children are the right size.
virtual S32 arrange( S32* width, S32* height );
virtual S32 getItemHeight() const;
void arrangeAll() { mArrangeGeneration++; }
S32 getArrangeGeneration() { return mArrangeGeneration; }
// applies filters to control visibility of items
virtual void filter( LLFolderViewFilter& filter);
void clearHoveredItem() { setHoveredItem(nullptr); }
LLFolderViewItem* getHoveredItem() const;
void setHoveredItem(LLFolderViewItem* itemp);
// Get the last selected item
virtual LLFolderViewItem* getCurSelectedItem( void );
selected_items_t& getSelectedItems( void );
// Record the selected item and pass it down the hierarchy.
virtual bool setSelection(LLFolderViewItem* selection, bool openitem,
bool take_keyboard_focus = true);
// This method is used to toggle the selection of an item. Walks
// children, and keeps track of selected objects.
virtual bool changeSelection(LLFolderViewItem* selection, bool selected);
virtual std::set<LLFolderViewItem*> getSelectionList() const;
// Make sure if ancestor is selected, descendants are not
void sanitizeSelection();
virtual void clearSelection();
void addToSelectionList(LLFolderViewItem* item);
void removeFromSelectionList(LLFolderViewItem* item);
// [SL:KB] - Patch: Inventory-DragDrop | Checked: 2014-02-04 (Catznip-3.6)
void setDragStart(S32 screen_x, S32 screen_y);
bool isOverDragThreshold(S32 screen_x, S32 screen_y);
// [/SL:KB]
bool startDrag();
void setDragAndDropThisFrame() { mDragAndDropThisFrame = true; }
void setDraggingOverItem(LLFolderViewItem* item) { mDraggingOverItem = item; }
LLFolderViewItem* getDraggingOverItem() { return mDraggingOverItem; }
// Deletion functionality
void removeSelectedItems();
void autoOpenItem(LLFolderViewFolder* item);
void closeAutoOpenedFolders();
bool autoOpenTest(LLFolderViewFolder* item);
bool isOpen() const { return true; } // root folder always open
// Copy & paste
virtual bool canCopy() const;
virtual void copy();
virtual bool canCut() const;
virtual void cut();
virtual bool canPaste() const;
virtual void paste();
LLFolderViewItem* getNextUnselectedItem();
// Public rename functionality - can only start the process
void startRenamingSelectedItem( void );
// LLView functionality
///*virtual*/ bool handleKey( KEY key, MASK mask, bool called_from_parent );
/*virtual*/ bool handleKeyHere( KEY key, MASK mask );
/*virtual*/ bool handleUnicodeCharHere(llwchar uni_char);
/*virtual*/ bool handleMouseDown( S32 x, S32 y, MASK mask );
/*virtual*/ bool handleDoubleClick( S32 x, S32 y, MASK mask );
/*virtual*/ bool handleRightMouseDown( S32 x, S32 y, MASK mask );
/*virtual*/ bool handleScrollWheel(S32 x, S32 y, S32 clicks); // <FS:Ansariel> FIRE-14223: Using mouse scroll while renaming an item moves line editor out of inventory floater
/*virtual*/ bool handleHover( S32 x, S32 y, MASK mask );
/*virtual*/ bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true);
/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) { setShowSelectionContext(false); }
virtual void draw();
virtual void deleteAllChildren();
void stopAutoScollining() {mNeedsScroll = false;}
void scrollToShowSelection();
void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect);
void setScrollContainer( LLScrollContainer* parent ) { mScrollContainer = parent; }
LLRect getVisibleRect();
bool search(LLFolderViewItem* first_item, const std::string &search_string, bool backward);
void setShowSelectionContext(bool show) { mShowSelectionContext = show; }
bool getShowSelectionContext();
void setShowSingleSelection(bool show);
bool getShowSingleSelection() { return mShowSingleSelection; }
F32 getSelectionFadeElapsedTime() { return mMultiSelectionFadeTimer.getElapsedTimeF32(); }
bool getUseEllipses() { return mUseEllipses; }
S32 getSelectedCount() { return (S32)mSelectedItems.size(); }
void update(); // needs to be called periodically (e.g. once per frame)
bool needsAutoSelect() { return mNeedsAutoSelect && !mAutoSelectOverride; }
bool needsAutoRename() { return mNeedsAutoRename; }
void setNeedsAutoRename(bool val) { mNeedsAutoRename = val; }
void setPinningSelectedItem(bool val) { mPinningSelectedItem = val; }
void setAutoSelectOverride(bool val) { mAutoSelectOverride = val; }
bool showItemLinkOverlays() { return mShowItemLinkOverlays; }
void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; }
void setEnableRegistrar(LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* registrar) { mEnableRegistrar = registrar; }
void setForceArrange(bool force) { mForceArrange = force; }
LLPanel* getParentPanel() { return mParentPanel.get(); }
// DEBUG only
void dumpSelectionInformation();
virtual S32 notify(const LLSD& info) ;
void setShowEmptyMessage(bool show_msg) { mShowEmptyMessage = show_msg; }
bool useLabelSuffix() { return mUseLabelSuffix; }
virtual void updateMenu();
void finishRenamingItem( void );
// Note: We may eventually have to move that method up the hierarchy to LLFolderViewItem.
LLHandle<LLFolderView> getHandle() const { return getDerivedHandle<LLFolderView>(); }
private:
void updateMenuOptions(LLMenuGL* menu);
void updateRenamerPosition();
static void onIdleUpdateMenu(void* user_data);
protected:
LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container.
void commitRename( const LLSD& data );
void onRenamerLost();
void closeRenamer( void );
bool isFolderSelected();
bool selectFirstItem();
bool selectLastItem();
bool addNoOptions(LLMenuGL* menu) const;
protected:
LLHandle<LLView> mPopupMenuHandle;
std::string mMenuFileName;
LLHandle<LLView> mHoveredItem;
selected_items_t mSelectedItems;
bool mKeyboardSelection,
mAllowMultiSelect,
mAllowDrag,
mShowEmptyMessage,
mShowFolderHierarchy,
mNeedsScroll,
mPinningSelectedItem,
mNeedsAutoSelect,
mAutoSelectOverride,
mNeedsAutoRename,
mUseLabelSuffix,
mDragAndDropThisFrame,
mShowItemLinkOverlays,
mShowSelectionContext,
mShowSingleSelection,
mSuppressFolderMenu,
mSingleFolderMode;
// Renaming variables and methods
LLFolderViewItem* mRenameItem; // The item currently being renamed
LLLineEditor* mRenamer;
LLRect mScrollConstraintRect;
LLDepthStack<LLFolderViewFolder> mAutoOpenItems;
LLFolderViewFolder* mAutoOpenCandidate;
LLFrameTimer mAutoOpenTimer;
LLFrameTimer mSearchTimer;
std::string mSearchString;
LLFrameTimer mMultiSelectionFadeTimer;
S32 mArrangeGeneration;
signal_t mSelectSignal;
signal_t mReshapeSignal;
S32 mSignalSelectCallback;
S32 mMinWidth;
// [SL:KB] - Patch: Inventory-DragDrop | Checked: 2014-02-04 (Catznip-3.6)
S32 mDragStartX;
S32 mDragStartY;
// [/SL:KB]
LLHandle<LLPanel> mParentPanel;
LLFolderViewModelInterface* mViewModel;
LLFolderViewGroupedItemModel* mGroupedItemModel;
/**
* Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll.
* NOTE: For now it's used only to cut LLFolderViewItem::mLabel text for Landmarks in Places Panel.
*/
bool mUseEllipses; // See EXT-719
/**
* Contains item under mouse pointer while dragging
*/
LLFolderViewItem* mDraggingOverItem; // See EXT-719
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;
boost::signals2::connection mRenamerTopLostSignalConnection;
bool mForceArrange;
public:
static F32 sAutoOpenTime;
LLTextBox* mStatusTextBox;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderViewFunctor
//
// Simple abstract base class for applying a functor to folders and
// items in a folder view hierarchy. This is suboptimal for algorithms
// that only work folders or only work on items, but I'll worry about
// that later when it's determined to be too slow.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFolderViewFunctor
{
public:
virtual ~LLFolderViewFunctor() {}
virtual void doFolder(LLFolderViewFolder* folder) = 0;
virtual void doItem(LLFolderViewItem* item) = 0;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLSelectFirstFilteredItem
//
// This will select the first *item* found in the hierarchy. If no item can be
// selected, the first matching folder will.
// Since doFolder() is done first but we prioritize item selection, we let the
// first filtered folder set the selection and raise a folder flag.
// The selection might be overridden by the first filtered item in doItem()
// which checks an item flag. Since doFolder() checks the item flag too, the first
// item will still be selected if items were to be done first and folders second.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLSelectFirstFilteredItem : public LLFolderViewFunctor
{
public:
LLSelectFirstFilteredItem() : mItemSelected(false), mFolderSelected(false) {}
virtual ~LLSelectFirstFilteredItem() {}
virtual void doFolder(LLFolderViewFolder* folder);
virtual void doItem(LLFolderViewItem* item);
bool wasItemSelected() { return mItemSelected || mFolderSelected; }
protected:
bool mItemSelected;
bool mFolderSelected;
};
class LLOpenFilteredFolders : public LLFolderViewFunctor
{
public:
LLOpenFilteredFolders() {}
virtual ~LLOpenFilteredFolders() {}
virtual void doFolder(LLFolderViewFolder* folder);
virtual void doItem(LLFolderViewItem* item);
};
class LLSaveFolderState : public LLFolderViewFunctor
{
public:
LLSaveFolderState() : mApply(false) {}
virtual ~LLSaveFolderState() {}
virtual void doFolder(LLFolderViewFolder* folder);
virtual void doItem(LLFolderViewItem* item) {}
void setApply(bool apply);
void clearOpenFolders() { mOpenFolders.clear(); }
bool hasOpenFolders() { return !mOpenFolders.empty(); }
protected:
std::set<LLUUID> mOpenFolders;
bool mApply;
};
class LLOpenFoldersWithSelection : public LLFolderViewFunctor
{
public:
LLOpenFoldersWithSelection() {}
virtual ~LLOpenFoldersWithSelection() {}
virtual void doFolder(LLFolderViewFolder* folder);
virtual void doItem(LLFolderViewItem* item);
};
class LLAllDescendentsPassedFilter : public LLFolderViewFunctor
{
public:
LLAllDescendentsPassedFilter() : mAllDescendentsPassedFilter(true) {}
/*virtual*/ ~LLAllDescendentsPassedFilter() {}
/*virtual*/ void doFolder(LLFolderViewFolder* folder);
/*virtual*/ void doItem(LLFolderViewItem* item);
bool allDescendentsPassedFilter() const { return mAllDescendentsPassedFilter; }
protected:
bool mAllDescendentsPassedFilter;
};
// Flags for buildContextMenu()
const U32 SUPPRESS_OPEN_ITEM = 0x1;
const U32 FIRST_SELECTED_ITEM = 0x2;
const U32 ITEM_IN_MULTI_SELECTION = 0x4;
#endif // LL_LLFOLDERVIEW_H
File diff suppressed because it is too large Load Diff
+522
View File
@@ -0,0 +1,522 @@
/**
* @file llfolderviewitem.h
* @brief Items and folders that can appear in a hierarchical folder view
*
* $LicenseInfo:firstyear=2001&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 LLFOLDERVIEWITEM_H
#define LLFOLDERVIEWITEM_H
#include "llflashtimer.h"
#include "llview.h"
#include "lluiimage.h"
#include "llfontvertexbuffer.h"
class LLFolderView;
class LLFolderViewModelItem;
class LLFolderViewFolder;
class LLFolderViewFunctor;
class LLFolderViewFilter;
class LLFolderViewModelInterface;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderViewItem
//
// An instance of this class represents a single item in a folder view
// such as an inventory item or a file.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFolderViewItem : public LLView
{
public:
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
Optional<LLUIImage*> folder_arrow_image,
selection_image;
Mandatory<LLFolderView*> root;
Mandatory<LLFolderViewModelItem*> listener;
Optional<S32> folder_indentation, // pixels
item_height,
item_top_pad;
Optional<time_t> creation_date;
Optional<bool> allow_wear;
Optional<bool> allow_drop;
Optional<LLUIColor> font_color;
Optional<LLUIColor> font_highlight_color;
Optional<S32> left_pad,
icon_pad,
icon_width,
text_pad,
text_pad_right,
arrow_size,
max_folder_item_overlap;
Optional<bool> single_folder_mode,
double_click_override;
// <FS:Ansariel> Inventory specials
Optional<bool> for_inventory;
Params();
};
static const S32 DEFAULT_LABEL_PADDING_RIGHT = 4;
// animation parameters
static const F32 FOLDER_CLOSE_TIME_CONSTANT,
FOLDER_OPEN_TIME_CONSTANT;
protected:
friend class LLUICtrlFactory;
friend class LLFolderViewModelItem;
LLFolderViewItem(const Params& p);
LLWString mLabel;
S32 mLabelWidth;
bool mLabelWidthDirty;
S32 mLabelPaddingRight;
LLFolderViewFolder* mParentFolder;
LLPointer<LLFolderViewModelItem> mViewModelItem;
LLFontGL::StyleFlags mLabelStyle;
LLWString mLabelSuffix;
bool mSuffixNeedsRefresh; //suffix and icons
LLUIImagePtr mIcon,
mIconOpen,
mIconOverlay;
S32 mLocalIndentation;
S32 mIndentation;
S32 mItemHeight;
// S32 mDragStartX,
// mDragStartY;
S32 mLeftPad,
mIconPad,
mIconWidth,
mTextPad,
mTextPadRight,
mArrowSize,
mMaxFolderItemOverlap;
F32 mControlLabelRotation;
LLFolderView* mRoot;
bool mHasVisibleChildren,
mIsCurSelection,
mDragAndDropTarget,
mIsMouseOverTitle,
mAllowWear,
mAllowDrop,
mSingleFolderMode,
mDoubleClickOverride,
mSelectPending,
mIsItemCut;
S32 mCutGeneration;
LLUIColor mFontColor;
LLUIColor mFontHighlightColor;
// <FS:Ansariel> Inventory specials
bool mForInventory;
S32 mItemTopPad;
// For now assuming all colors are the same in derived classes.
static LLUIColor sFgColor;
static LLUIColor sFgDisabledColor;
static LLUIColor sHighlightBgColor;
static LLUIColor sFlashBgColor;
static LLUIColor sFocusOutlineColor;
static LLUIColor sMouseOverColor;
static LLUIColor sFilterBGColor;
static LLUIColor sFilterTextColor;
static LLUIColor sSuffixColor;
static LLUIColor sSearchStatusColor;
// <FS:Ansariel> Special for protected items
static LLUIColor sProtectedColor;
// this is an internal method used for adding items to folders. A
// no-op at this level, but reimplemented in derived classes.
virtual void addItem(LLFolderViewItem*) { }
virtual void addFolder(LLFolderViewFolder*) { }
virtual bool isHighlightAllowed();
virtual bool isHighlightActive();
virtual bool isFadeItem();
virtual bool isFlashing() { return false; }
virtual void setFlashState(bool) { }
static LLFontGL* getLabelFontForStyle(U8 style);
const LLFontGL* getLabelFont();
bool mIsSelected;
public:
static void initClass();
static void cleanupClass();
bool postBuild();
virtual void openItem( void );
void arrangeAndSet(bool set_selection, bool take_keyboard_focus);
virtual ~LLFolderViewItem( void );
// addToFolder() returns true if it succeeds. false otherwise
virtual void addToFolder(LLFolderViewFolder* folder);
// Finds width and height of this object and it's children. Also
// makes sure that this view and it's children are the right size.
virtual S32 arrange( S32* width, S32* height );
virtual S32 getItemHeight() const;
virtual S32 getLabelXPos();
S32 getIconPad();
S32 getTextPad();
// If 'selection' is 'this' then note that otherwise ignore.
// Returns true if this item ends up being selected.
virtual bool setSelection(LLFolderViewItem* selection, bool openitem, bool take_keyboard_focus);
// This method is used to set the selection state of an item.
// If 'selection' is 'this' then note selection.
// Returns true if the selection state of this item was changed.
virtual bool changeSelection(LLFolderViewItem* selection, bool selected);
// this method is used to deselect this element
void deselectItem();
// this method is used to select this element
virtual void selectItem();
// gets multiple-element selection
virtual std::set<LLFolderViewItem*> getSelectionList() const;
// Returns true is this object and all of its children can be removed (deleted by user)
virtual bool isRemovable();
// Returns true is this object and all of its children can be moved
virtual bool isMovable();
// destroys this item recursively
virtual void destroyView();
bool isSelected() const { return mIsSelected; }
bool isInSelection() const;
void setUnselected() { mIsSelected = false; }
void setIsCurSelection(bool select) { mIsCurSelection = select; }
bool getIsCurSelection() const { return mIsCurSelection; }
bool hasVisibleChildren() const { return mHasVisibleChildren; }
// true if object can't have children
virtual bool isFolderComplete() { return true; }
// true if object can't have children
virtual bool areChildrenInited() { return true; }
virtual void setChildrenInited(bool inited) { }
// Call through to the viewed object and return true if it can be
// removed. Returns true if it's removed.
//virtual bool removeRecursively(bool single_item);
bool remove();
// Build an appropriate context menu for the item. Flags unused.
void buildContextMenu(class LLMenuGL& menu, U32 flags);
// This method returns the actual name of the thing being
// viewed. This method will ask the viewed object itself.
const std::string& getName( void ) const;
// This method returns the label displayed on the view. This
// method was primarily added to allow sorting on the folder
// contents possible before the entire view has been constructed.
const LLWString& getLabel() const { return mLabel; }
LLFolderViewFolder* getParentFolder( void ) { return mParentFolder; }
const LLFolderViewFolder* getParentFolder( void ) const { return mParentFolder; }
void setParentFolder(LLFolderViewFolder* parent) { mParentFolder = parent; }
LLFolderViewItem* getNextOpenNode( bool include_children = true );
LLFolderViewItem* getPreviousOpenNode( bool include_children = true );
const LLFolderViewModelItem* getViewModelItem( void ) const { return mViewModelItem; }
LLFolderViewModelItem* getViewModelItem( void ) { return mViewModelItem; }
const LLFolderViewModelInterface* getFolderViewModel( void ) const;
LLFolderViewModelInterface* getFolderViewModel( void );
// just rename the object.
void rename(const std::string& new_name);
// Show children
virtual void setOpen(bool open = true) {};
virtual bool isOpen() const { return false; }
virtual LLFolderView* getRoot();
virtual const LLFolderView* getRoot() const;
bool isDescendantOf( const LLFolderViewFolder* potential_ancestor );
S32 getIndentation() const { return mIndentation; }
virtual bool passedFilter(S32 filter_generation = -1);
virtual bool isPotentiallyVisible(S32 filter_generation = -1);
// refresh information from the object being viewed.
// refreshes label, suffixes and sets icons. Expensive!
// Causes filter update
virtual void refresh();
// refreshes suffixes and sets icons. Expensive!
// Does not need filter update
virtual void refreshSuffix();
bool isSingleFolderMode() { return mSingleFolderMode; }
// LLView functionality
virtual bool handleRightMouseDown( S32 x, S32 y, MASK mask );
virtual bool handleMouseDown( S32 x, S32 y, MASK mask );
virtual bool handleHover( S32 x, S32 y, MASK mask );
virtual bool handleMouseUp( S32 x, S32 y, MASK mask );
virtual bool handleDoubleClick( S32 x, S32 y, MASK mask );
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
//virtual LLView* findChildView(const std::string& name, bool recurse) const { return LLView::findChildView(name, recurse); }
// virtual void handleDropped();
virtual void draw();
void drawOpenFolderArrow();
void drawHighlight(bool showContent, bool hasKeyboardFocus, const LLUIColor& selectColor, const LLUIColor& flashColor, const LLUIColor& outlineColor, const LLUIColor& mouseOverColor);
void drawLabel(const LLFontGL* font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x);
virtual bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
// <ND/> Don't bother with unneeded tooltips in inventor
/*virtual*/ bool handleToolTip(S32 x, S32 y, MASK mask);
private:
static std::map<U8, LLFontGL*> sFonts; // map of styles to fonts
static S32 sTopPad;
static LLUIImagePtr sFolderArrowImg;
static LLUIImagePtr sSelectionImg;
static LLFontGL* sSuffixFont;
LLFontVertexBuffer mLabelFontBuffer;
LLFontVertexBuffer mSuffixFontBuffer;
LLFontGL* pLabelFont{nullptr};
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderViewFolder
//
// An instance of an LLFolderViewFolder represents a collection of
// more folders and items. This is used to build the hierarchy of
// items found in the folder view.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFolderViewFolder : public LLFolderViewItem
{
protected:
LLFolderViewFolder( const LLFolderViewItem::Params& );
friend class LLUICtrlFactory;
void updateLabelRotation();
virtual bool isCollapsed() { return false; }
public:
typedef std::list<LLFolderViewItem*> items_t;
typedef std::list<LLFolderViewFolder*> folders_t;
protected:
items_t mItems;
folders_t mFolders;
bool mIsOpen;
bool mExpanderHighlighted;
F32 mCurHeight;
F32 mTargetHeight;
F32 mAutoOpenCountdown;
S32 mLastArrangeGeneration;
S32 mLastCalculatedWidth;
bool mIsFolderComplete; // indicates that some children were not loaded/added yet
bool mAreChildrenInited; // indicates that no children were initialized
public:
typedef enum e_recurse_type
{
RECURSE_NO,
RECURSE_UP,
RECURSE_DOWN,
RECURSE_UP_DOWN
} ERecurseType;
virtual ~LLFolderViewFolder( void );
LLFolderViewItem* getNextFromChild( LLFolderViewItem*, bool include_children = true );
LLFolderViewItem* getPreviousFromChild( LLFolderViewItem*, bool include_children = true );
// addToFolder() returns true if it succeeds. false otherwise
virtual void addToFolder(LLFolderViewFolder* folder);
// Finds width and height of this object and it's children. Also
// makes sure that this view and it's children are the right size.
virtual S32 arrange( S32* width, S32* height );
bool needsArrange();
bool descendantsPassedFilter(S32 filter_generation = -1);
// Passes selection information on to children and record
// selection information if necessary.
// Returns true if this object (or a child) ends up being selected.
// If 'openitem' is true then folders are opened up along the way to the selection.
virtual bool setSelection(LLFolderViewItem* selection, bool openitem, bool take_keyboard_focus = true);
// This method is used to change the selection of an item.
// Recursively traverse all children; if 'selection' is 'this' then change
// the select status if necessary.
// Returns true if the selection state of this folder, or of a child, was changed.
virtual bool changeSelection(LLFolderViewItem* selection, bool selected);
// this method is used to group select items
void extendSelectionTo(LLFolderViewItem* selection);
// Returns true is this object and all of its children can be removed.
virtual bool isRemovable();
// Returns true is this object and all of its children can be moved
virtual bool isMovable();
// destroys this folder, and all children
virtual void destroyView();
void destroyRoot();
// whether known children are fully loaded (arrange sets to true)
virtual bool isFolderComplete() { return mIsFolderComplete; }
// whether known children are fully built
virtual bool areChildrenInited() { return mAreChildrenInited; }
virtual void setChildrenInited(bool inited) { mAreChildrenInited = inited; }
// extractItem() removes the specified item from the folder, but
// doesn't delete it.
virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true);
// This function is called by a child that needs to be resorted.
void resort(LLFolderViewItem* item);
void setAutoOpenCountdown(F32 countdown) { mAutoOpenCountdown = countdown; }
// folders can be opened. This will usually be called by internal
// methods.
virtual void toggleOpen();
// Force a folder open or closed
virtual void setOpen(bool openitem = true);
// Called when a child is refreshed.
virtual void requestArrange();
// internal method which doesn't update the entire view. This
// method was written because the list iterators destroy the state
// of other iterations, thus, we can't arrange while iterating
// through the children (such as when setting which is selected.
virtual void setOpenArrangeRecursively(bool openitem, ERecurseType recurse = RECURSE_NO);
// Get the current state of the folder.
virtual bool isOpen() const { return mIsOpen; }
// special case if an object is dropped on the child.
bool handleDragAndDropFromChild(MASK mask,
bool drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
// Just apply this functor to the folder's immediate children.
void applyFunctorToChildren(LLFolderViewFunctor& functor);
// apply this functor to the folder's descendants.
void applyFunctorRecursively(LLFolderViewFunctor& functor);
virtual void openItem( void );
// LLView functionality
virtual bool handleHover(S32 x, S32 y, MASK mask);
virtual bool handleRightMouseDown( S32 x, S32 y, MASK mask );
virtual bool handleMouseDown( S32 x, S32 y, MASK mask );
virtual bool handleDoubleClick( S32 x, S32 y, MASK mask );
virtual bool handleDragAndDrop(S32 x, S32 y, MASK mask,
bool drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
bool handleDragAndDropToThisFolder(MASK mask,
bool drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
virtual void draw();
folders_t::iterator getFoldersBegin() { return mFolders.begin(); }
folders_t::iterator getFoldersEnd() { return mFolders.end(); }
folders_t::size_type getFoldersCount() const { return mFolders.size(); }
items_t::const_iterator getItemsBegin() const { return mItems.begin(); }
items_t::const_iterator getItemsEnd() const { return mItems.end(); }
items_t::size_type getItemsCount() const { return mItems.size(); }
LLFolderViewFolder* getCommonAncestor(LLFolderViewItem* item_a, LLFolderViewItem* item_b, bool& reverse);
void gatherChildRangeExclusive(LLFolderViewItem* start, LLFolderViewItem* end, bool reverse, std::vector<LLFolderViewItem*>& items);
// internal functions for tracking folders and items separately
// use addToFolder() virtual method to ensure folders are always added to mFolders
// and not mItems
void addItem(LLFolderViewItem* item);
void addFolder( LLFolderViewFolder* folder);
//WARNING: do not call directly...use the appropriate LLFolderViewModel-derived class instead
template<typename SORT_FUNC> void sortFolders(const SORT_FUNC& func) { mFolders.sort(func); }
template<typename SORT_FUNC> void sortItems(const SORT_FUNC& func) { mItems.sort(func); }
};
typedef std::deque<LLFolderViewItem*> folder_view_item_deque;
class LLFolderViewGroupedItemModel: public LLRefCount
{
public:
virtual void groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu) = 0;
};
#endif // LLFOLDERVIEWITEM_H
+69
View File
@@ -0,0 +1,69 @@
/**
* @file llfolderviewmodel.cpp
* @brief Implementation of the view model collection of classes.
*
* $LicenseInfo:firstyear=2001&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$
*/
#include "linden_common.h"
#include "llfolderviewmodel.h"
#include "lltrans.h"
bool LLFolderViewModelCommon::needsSort(LLFolderViewModelItem* item)
{
return item->getSortVersion() < mTargetSortVersion;
}
std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder)
{
if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter().getCurrentGeneration())
{
return LLTrans::getString("Searching");
}
else
{
return getFilter().getEmptyLookupMessage(is_empty_folder);
}
}
void LLFolderViewModelCommon::filter()
{
const S32 MAX_FILTER_TIME = 10;
getFilter().resetTime(MAX_FILTER_TIME);
mFolderView->getViewModelItem()->filter(getFilter());
}
bool LLFolderViewModelItemCommon::hasFilterStringMatch()
{
return mStringMatchOffsetFilter != std::string::npos;
}
std::string::size_type LLFolderViewModelItemCommon::getFilterStringOffset()
{
return mStringMatchOffsetFilter;
}
std::string::size_type LLFolderViewModelItemCommon::getFilterStringSize()
{
return mRootViewModel.getFilter().getFilterStringSize();
}
+488
View File
@@ -0,0 +1,488 @@
/**
* @file llfolderviewmodel.h
*
* $LicenseInfo:firstyear=2001&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 LLFOLDERVIEWMODEL_H
#define LLFOLDERVIEWMODEL_H
#include "llfontgl.h" // just for StyleFlags enum
#include "llfolderview.h"
// These are grouping of inventory types.
// Order matters when sorting system folders to the top.
enum EInventorySortGroup
{
SG_SYSTEM_FOLDER,
SG_TRASH_FOLDER,
SG_NORMAL_FOLDER,
SG_ITEM
};
class LLFontGL;
class LLInventoryModel;
class LLMenuGL;
class LLUIImage;
class LLUUID;
class LLFolderViewItem;
class LLFolderViewFolder;
class LLFolderViewFilter
{
public:
enum EFilterModified
{
FILTER_NONE, // nothing to do, already filtered
FILTER_RESTART, // restart filtering from scratch
FILTER_LESS_RESTRICTIVE, // existing filtered items will certainly pass this filter
FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one
};
public:
LLFolderViewFilter() {}
virtual ~LLFolderViewFilter() {}
// +-------------------------------------------------------------------+
// + Execution And Results
// +-------------------------------------------------------------------+
virtual bool check(const LLFolderViewModelItem* item) = 0;
virtual bool checkFolder(const LLFolderViewModelItem* folder) const = 0;
virtual void setEmptyLookupMessage(const std::string& message) = 0;
virtual std::string getEmptyLookupMessage(bool is_empty_folder = false) const = 0;
virtual bool showAllResults() const = 0;
virtual std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const = 0;
virtual std::string::size_type getFilterStringSize() const = 0;
// +-------------------------------------------------------------------+
// + Status
// +-------------------------------------------------------------------+
virtual bool isActive() const = 0;
virtual bool isModified() const = 0;
virtual void clearModified() = 0;
virtual const std::string& getName() const = 0;
virtual const std::string& getFilterText() = 0;
//RN: this is public to allow system to externally force a global refilter
virtual void setModified(EFilterModified behavior = FILTER_RESTART) = 0;
// +-------------------------------------------------------------------+
// + Time
// +-------------------------------------------------------------------+
virtual void resetTime(S32 timeout) = 0;
virtual bool isTimedOut() = 0;
// +-------------------------------------------------------------------+
// + Default
// +-------------------------------------------------------------------+
virtual bool isDefault() const = 0;
virtual bool isNotDefault() const = 0;
virtual void markDefault() = 0;
virtual void resetDefault() = 0;
// +-------------------------------------------------------------------+
// + Generation
// +-------------------------------------------------------------------+
virtual S32 getCurrentGeneration() const = 0;
virtual S32 getFirstSuccessGeneration() const = 0;
virtual S32 getFirstRequiredGeneration() const = 0;
};
class LLFolderViewModelInterface
{
public:
LLFolderViewModelInterface()
{}
virtual ~LLFolderViewModelInterface() {}
virtual void requestSortAll() = 0;
virtual void sort(class LLFolderViewFolder*) = 0;
virtual void filter() = 0;
virtual bool contentsReady() = 0;
virtual bool isFolderComplete(class LLFolderViewFolder*) = 0;
virtual void setFolderView(LLFolderView* folder_view) = 0;
virtual LLFolderViewFilter& getFilter() = 0;
virtual const LLFolderViewFilter& getFilter() const = 0;
virtual std::string getStatusText(bool is_empty_folder = false) = 0;
virtual bool startDrag(std::vector<LLFolderViewModelItem*>& items) = 0;
};
// This is an abstract base class that users of the folderview classes
// would use to bridge the folder view with the underlying data
class LLFolderViewModelItem : public LLRefCount
{
public:
LLFolderViewModelItem()
{}
virtual ~LLFolderViewModelItem() { }
virtual void update() {} //called when drawing
virtual const std::string& getName() const = 0;
virtual const std::string& getDisplayName() const = 0;
virtual const std::string& getSearchableName() const = 0;
virtual std::string getSearchableDescription() const = 0;
virtual std::string getSearchableCreatorName()const = 0;
virtual std::string getSearchableUUIDString() const = 0;
virtual std::string getSearchableAll() const = 0; // <FS:Ansariel> Zi's extended inventory search
virtual LLPointer<LLUIImage> getIcon() const = 0;
virtual LLPointer<LLUIImage> getIconOpen() const { return getIcon(); }
virtual LLPointer<LLUIImage> getIconOverlay() const { return NULL; }
virtual LLFontGL::StyleFlags getLabelStyle() const = 0;
virtual std::string getLabelSuffix() const = 0;
virtual void openItem( void ) = 0;
virtual void closeItem( void ) = 0;
virtual void selectItem(void) = 0;
virtual void navigateToFolder(bool new_window = false, bool change_mode = false) = 0;
virtual bool isItemWearable() const { return false; }
virtual bool isItemRenameable() const = 0;
virtual bool renameItem(const std::string& new_name) = 0;
virtual bool isItemMovable( void ) const = 0; // Can be moved to another folder
virtual void move( LLFolderViewModelItem* parent_listener ) = 0;
virtual bool isItemRemovable( bool check_worn = true ) const = 0; // Can be destroyed
virtual bool removeItem() = 0;
virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0;
virtual bool isItemCopyable(bool can_copy_as_link = true) const = 0;
virtual bool copyToClipboard() const = 0;
virtual bool cutToClipboard() = 0;
virtual bool isCutToClipboard() { return false; };
virtual bool isClipboardPasteable() const = 0;
virtual void pasteFromClipboard() = 0;
virtual void pasteLinkFromClipboard() = 0;
virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0;
virtual bool potentiallyVisible() = 0; // is the item definitely visible or we haven't made up our minds yet?
virtual bool filter( LLFolderViewFilter& filter) = 0;
virtual bool passedFilter(S32 filter_generation = -1) = 0;
virtual bool descendantsPassedFilter(S32 filter_generation = -1) = 0;
virtual void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) = 0;
virtual void setPassedFolderFilter(bool passed, S32 filter_generation) = 0;
virtual void dirtyFilter() = 0;
virtual void dirtyDescendantsFilter() = 0;
virtual bool hasFilterStringMatch() = 0;
virtual std::string::size_type getFilterStringOffset() = 0;
virtual std::string::size_type getFilterStringSize() = 0;
virtual S32 getLastFilterGeneration() const = 0;
virtual S32 getMarkedDirtyGeneration() const = 0;
virtual bool hasChildren() const = 0;
virtual void addChild(LLFolderViewModelItem* child) = 0;
virtual void removeChild(LLFolderViewModelItem* child) = 0;
virtual void clearChildren() = 0;
// This method will be called to determine if a drop can be
// performed, and will set drop to true if a drop is
// requested. Returns true if a drop is possible/happened,
// otherwise false.
virtual bool dragOrDrop(MASK mask, bool drop,
EDragAndDropType cargo_type,
void* cargo_data,
std::string& tooltip_msg) = 0;
virtual void requestSort() = 0;
virtual S32 getSortVersion() = 0;
virtual void setSortVersion(S32 version) = 0;
virtual void setParent(LLFolderViewModelItem* parent) = 0;
virtual bool hasParent() = 0;
// <FS:ND/>
virtual LLFolderViewModelItem* getParent() const = 0;
// <FS:Ansariel> Special for locked items
virtual bool isLocked() const { return false; }
// <FS:Ansariel> FIRE-29342: Protect folder option
virtual bool isProtected() const { return false; }
protected:
friend class LLFolderViewItem;
virtual void setFolderViewItem(LLFolderViewItem* folder_view_item) = 0;
};
class LLFolderViewModelItemCommon : public LLFolderViewModelItem
{
public:
LLFolderViewModelItemCommon(LLFolderViewModelInterface& root_view_model)
: mSortVersion(-1),
mPassedFilter(true),
mPassedFolderFilter(true),
mStringMatchOffsetFilter(std::string::npos),
mStringFilterSize(0),
mFolderViewItem(NULL),
mLastFilterGeneration(-1),
mLastFolderFilterGeneration(-1),
mMarkedDirtyGeneration(-1),
mMostFilteredDescendantGeneration(-1),
mParent(NULL),
mRootViewModel(root_view_model)
{
mChildren.clear();
}
void requestSort() { mSortVersion = -1; }
S32 getSortVersion() { return mSortVersion; }
void setSortVersion(S32 version) { mSortVersion = version;}
S32 getLastFilterGeneration() const { return mLastFilterGeneration; }
S32 getLastFolderFilterGeneration() const { return mLastFolderFilterGeneration; }
S32 getMarkedDirtyGeneration() const { return mMarkedDirtyGeneration; }
void dirtyFilter()
{
if(mMarkedDirtyGeneration < 0)
{
mMarkedDirtyGeneration = mLastFilterGeneration;
}
mLastFilterGeneration = -1;
mLastFolderFilterGeneration = -1;
// bubble up dirty flag all the way to root
if (mParent)
{
mParent->dirtyFilter();
}
}
void dirtyDescendantsFilter()
{
mMostFilteredDescendantGeneration = -1;
if (mParent)
{
mParent->dirtyDescendantsFilter();
}
}
bool hasFilterStringMatch();
std::string::size_type getFilterStringOffset();
std::string::size_type getFilterStringSize();
typedef std::list<LLFolderViewModelItem*> child_list_t;
virtual void addChild(LLFolderViewModelItem* child)
{
mChildren.push_back(child);
child->setParent(this);
dirtyFilter();
requestSort();
}
virtual void removeChild(LLFolderViewModelItem* child)
{
mChildren.remove(child);
child->setParent(NULL);
dirtyDescendantsFilter();
dirtyFilter();
}
virtual void clearChildren()
{
// We are working with models that belong to views as LLPointers, clean the list, let poiters handle the rest
std::for_each(mChildren.begin(), mChildren.end(), [](LLFolderViewModelItem* c) {c->setParent(NULL); });
mChildren.clear();
dirtyDescendantsFilter();
dirtyFilter();
}
child_list_t::const_iterator getChildrenBegin() const { return mChildren.begin(); }
child_list_t::const_iterator getChildrenEnd() const { return mChildren.end(); }
child_list_t::size_type getChildrenCount() const { return mChildren.size(); }
void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0)
{
mPassedFilter = passed;
mLastFilterGeneration = filter_generation;
mStringMatchOffsetFilter = string_offset;
mStringFilterSize = string_size;
mMarkedDirtyGeneration = -1;
}
void setPassedFolderFilter(bool passed, S32 filter_generation)
{
mPassedFolderFilter = passed;
mLastFolderFilterGeneration = filter_generation;
}
virtual bool potentiallyVisible()
{
return passedFilter() // we've passed the filter
|| (getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration()) // or we don't know yet
|| descendantsPassedFilter();
}
virtual bool passedFilter(S32 filter_generation = -1)
{
if (filter_generation < 0)
{
filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration();
}
bool passed_folder_filter = mPassedFolderFilter && (mLastFolderFilterGeneration >= filter_generation);
bool passed_filter = mPassedFilter && (mLastFilterGeneration >= filter_generation);
return passed_folder_filter && (passed_filter || descendantsPassedFilter(filter_generation));
}
virtual bool descendantsPassedFilter(S32 filter_generation = -1)
{
if (filter_generation < 0)
{
filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration();
}
return mMostFilteredDescendantGeneration >= filter_generation;
}
protected:
virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; }
virtual bool hasParent() { return mParent != NULL; }
// <FS:ND/>
virtual LLFolderViewModelItem* getParent() const { return mParent; }
S32 mSortVersion;
bool mPassedFilter;
bool mPassedFolderFilter;
std::string::size_type mStringMatchOffsetFilter;
std::string::size_type mStringFilterSize;
S32 mLastFilterGeneration,
mLastFolderFilterGeneration,
mMostFilteredDescendantGeneration,
mMarkedDirtyGeneration;
child_list_t mChildren;
LLFolderViewModelItem* mParent;
LLFolderViewModelInterface& mRootViewModel;
void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;}
LLFolderViewItem* mFolderViewItem;
};
class LLFolderViewModelCommon : public LLFolderViewModelInterface
{
public:
LLFolderViewModelCommon()
: mTargetSortVersion(0),
mFolderView(NULL)
{}
virtual void requestSortAll()
{
// sort everything
mTargetSortVersion++;
}
virtual std::string getStatusText(bool is_empty_folder = false);
virtual void filter();
void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;}
protected:
bool needsSort(class LLFolderViewModelItem* item);
S32 mTargetSortVersion;
LLFolderView* mFolderView;
};
template <typename SORT_TYPE, typename ITEM_TYPE, typename FOLDER_TYPE, typename FILTER_TYPE>
class LLFolderViewModel : public LLFolderViewModelCommon
{
public:
typedef SORT_TYPE SortType;
typedef ITEM_TYPE ItemType;
typedef FOLDER_TYPE FolderType;
typedef FILTER_TYPE FilterType;
LLFolderViewModel(SortType* sorter, FilterType* filter)
: mSorter(sorter),
mFilter(filter)
{}
virtual ~LLFolderViewModel() {}
virtual SortType& getSorter() { return *mSorter; }
virtual const SortType& getSorter() const { return *mSorter; }
virtual void setSorter(const SortType& sorter) { mSorter.reset(new SortType(sorter)); requestSortAll(); }
virtual FilterType& getFilter() { return *mFilter; }
virtual const FilterType& getFilter() const { return *mFilter; }
virtual void setFilter(const FilterType& filter) { mFilter.reset(new FilterType(filter)); }
// By default, we assume the content is available. If a network fetch mechanism is implemented for the model,
// this method needs to be overloaded and return the relevant fetch status.
virtual bool contentsReady() { return true; }
virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; }
struct ViewModelCompare
{
ViewModelCompare(const SortType& sorter)
: mSorter(sorter)
{}
bool operator () (const LLFolderViewItem* a, const LLFolderViewItem* b) const
{
return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem()));
}
bool operator () (const LLFolderViewFolder* a, const LLFolderViewFolder* b) const
{
return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem()));
}
const SortType& mSorter;
};
void sort(LLFolderViewFolder* folder)
{
if (needsSort(folder->getViewModelItem()))
{
folder->sortFolders(ViewModelCompare(getSorter()));
folder->sortItems(ViewModelCompare(getSorter()));
folder->getViewModelItem()->setSortVersion(mTargetSortVersion);
folder->requestArrange();
}
}
protected:
std::unique_ptr<SortType> mSorter;
std::unique_ptr<FilterType> mFilter;
};
#endif // LLFOLDERVIEWMODEL_H
+140
View File
@@ -0,0 +1,140 @@
/**
* @file llfunctorregistry.h
* @author Kent Quirk
* @brief Maintains a registry of named callback functors taking a single LLSD parameter
*
* $LicenseInfo:firstyear=2008&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_LLFUNCTORREGISTRY_H
#define LL_LLFUNCTORREGISTRY_H
#include <string>
#include <map>
#include <boost/function.hpp>
#include "llsd.h"
#include "llsingleton.h"
/**
* @class LLFunctorRegistry
* @brief Maintains a collection of named functors for remote binding
* (mainly for use in callbacks from notifications and other signals)
* @see LLNotifications
*
* This class maintains a collection of named functors in a singleton.
* We wanted to be able to persist notifications with their callbacks
* across restarts of the viewer; we couldn't store functors that way.
* Using this registry, systems that require a functor to be maintained
* long term can register it at system startup, and then pass in the
* functor by name.
*/
template <typename FUNCTOR_TYPE>
class LLFunctorRegistry : public LLSingleton<LLFunctorRegistry<FUNCTOR_TYPE> >
{
LLSINGLETON(LLFunctorRegistry);
LOG_CLASS(LLFunctorRegistry);
public:
typedef FUNCTOR_TYPE ResponseFunctor;
typedef typename std::map<std::string, FUNCTOR_TYPE> FunctorMap;
bool registerFunctor(const std::string& name, ResponseFunctor f)
{
bool retval = true;
if (mMap.count(name) == 0)
{
mMap[name] = f;
}
else
{
LL_ERRS() << "attempt to store duplicate name '" << name << "' in LLFunctorRegistry. NOT ADDED." << LL_ENDL;
retval = false;
}
return retval;
}
bool unregisterFunctor(const std::string& name)
{
if (mMap.count(name) == 0)
{
LL_WARNS() << "trying to remove '" << name << "' from LLFunctorRegistry but it's not there." << LL_ENDL;
return false;
}
mMap.erase(name);
return true;
}
FUNCTOR_TYPE getFunctor(const std::string& name)
{
if (mMap.count(name) != 0)
{
return mMap[name];
}
else
{
LL_DEBUGS() << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << LL_ENDL;
return mMap[LOGFUNCTOR];
}
}
const std::string LOGFUNCTOR;
const std::string DONOTHING;
private:
static void log_functor(const LLSD& notification, const LLSD& payload)
{
LL_DEBUGS() << "log_functor called with payload: " << payload << LL_ENDL;
}
static void do_nothing(const LLSD& notification, const LLSD& payload)
{
// what the sign sez
}
FunctorMap mMap;
};
template <typename FUNCTOR_TYPE>
LLFunctorRegistry<FUNCTOR_TYPE>::LLFunctorRegistry() :
LOGFUNCTOR("LogFunctor"), DONOTHING("DoNothing")
{
mMap[LOGFUNCTOR] = log_functor;
mMap[DONOTHING] = do_nothing;
}
template <typename FUNCTOR_TYPE>
class LLFunctorRegistration
{
public:
LLFunctorRegistration(const std::string& name, FUNCTOR_TYPE functor)
{
LLFunctorRegistry<FUNCTOR_TYPE>::instance().registerFunctor(name, functor);
}
};
#endif//LL_LLFUNCTORREGISTRY_H
+44
View File
@@ -0,0 +1,44 @@
/**
* @file llhelp.h
* @brief Abstract interface to the Help system
* @author Tofu Linden
*
* $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_LLHELP_H
#define LL_LLHELP_H
class LLHelp
{
public:
virtual void showTopic(const std::string &topic) = 0;
virtual std::string getURL(const std::string &topic) = 0;
// return default (fallback) topic name suitable for showTopic()
virtual std::string defaultTopic() = 0;
// return topic to use before the user logs in
virtual std::string preLoginTopic() = 0;
// return topic to use for the top-level help, invoked by F1
virtual std::string f1HelpTopic() = 0;
};
#endif // headerguard
+173
View File
@@ -0,0 +1,173 @@
/**
* @file lliconctrl.cpp
* @brief LLIconCtrl base class
*
* $LicenseInfo:firstyear=2001&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$
*/
#include "linden_common.h"
#include "lliconctrl.h"
// Linden library includes
// Project includes
#include "llcontrol.h"
#include "llui.h"
#include "lluictrlfactory.h"
#include "lluiimage.h"
#include "llwindow.h"
#include "llgltexture.h"
static LLDefaultChildRegistry::Register<LLIconCtrl> r("icon");
LLIconCtrl::Params::Params()
: image("image_name"),
color("color"),
use_draw_context_alpha("use_draw_context_alpha", true),
interactable("interactable", false),
scale_image("scale_image"),
min_width("min_width", 0),
min_height("min_height", 0)
{}
LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p)
: LLUICtrl(p),
mColor(p.color()),
mImagep(p.image),
mUseDrawContextAlpha(p.use_draw_context_alpha),
mInteractable(p.interactable),
mPriority(0),
mMinWidth(p.min_width),
mMinHeight(p.min_height),
mMaxWidth(0),
mMaxHeight(0)
{
if (mImagep.notNull())
{
LLUICtrl::setValue(mImagep->getName());
}
}
LLIconCtrl::~LLIconCtrl()
{
mImagep = NULL;
}
void LLIconCtrl::draw()
{
if( mImagep.notNull() )
{
const F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
mImagep->draw(getLocalRect(), mColor.get() % alpha );
}
LLUICtrl::draw();
}
bool LLIconCtrl::handleHover(S32 x, S32 y, MASK mask)
{
if (mInteractable && getEnabled())
{
getWindow()->setCursor(UI_CURSOR_HAND);
return true;
}
return LLUICtrl::handleHover(x, y, mask);
}
void LLIconCtrl::onVisibilityChange(bool new_visibility)
{
LLUICtrl::onVisibilityChange(new_visibility);
if (mPriority == LLGLTexture::BOOST_ICON)
{
if (new_visibility)
{
loadImage(getValue(), mPriority);
}
else
{
mImagep = nullptr;
}
}
}
// virtual
// value might be a string or a UUID
void LLIconCtrl::setValue(const LLSD& value)
{
setValue(value, mPriority);
}
void LLIconCtrl::setValue(const LLSD& value, S32 priority)
{
LLSD tvalue(value);
if (value.isString() && LLUUID::validate(value.asString()))
{
//RN: support UUIDs masquerading as strings
tvalue = LLSD(LLUUID(value.asString()));
}
LLUICtrl::setValue(tvalue);
loadImage(tvalue, priority);
}
void LLIconCtrl::loadImage(const LLSD& tvalue, S32 priority)
{
if(mPriority == LLGLTexture::BOOST_ICON && !getVisible()) return;
if (tvalue.isUUID())
{
mImagep = LLUI::getUIImageByID(tvalue.asUUID(), priority);
}
else
{
mImagep = LLUI::getUIImage(tvalue.asString(), priority);
}
if(mImagep.notNull()
&& mImagep->getImage().notNull()
&& mMinWidth
&& mMinHeight)
{
S32 desired_draw_width = llmax(mMinWidth, mImagep->getWidth());
S32 desired_draw_height = llmax(mMinHeight, mImagep->getHeight());
if (mMaxWidth && mMaxHeight)
{
desired_draw_width = llmin(desired_draw_width, mMaxWidth);
desired_draw_height = llmin(desired_draw_height, mMaxHeight);
}
mImagep->getImage()->setKnownDrawSize(desired_draw_width, desired_draw_height);
}
}
std::string LLIconCtrl::getImageName() const
{
if (getValue().isString())
return getValue().asString();
else
return std::string();
}
+107
View File
@@ -0,0 +1,107 @@
/**
* @file lliconctrl.h
* @brief LLIconCtrl base class
*
* $LicenseInfo:firstyear=2001&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_LLICONCTRL_H
#define LL_LLICONCTRL_H
#include "lluuid.h"
#include "v4color.h"
#include "lluictrl.h"
#include "lluiimage.h"
class LLTextBox;
class LLUICtrlFactory;
//
// Classes
//
// Class for diplaying named UI textures
// Do not use for displaying textures from network,
// UI textures are stored permanently!
class LLIconCtrl
: public LLUICtrl
{
public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<LLUIImage*> image;
Optional<LLUIColor> color;
Optional<bool> use_draw_context_alpha,
interactable;
Optional<S32> min_width,
min_height;
Ignored scale_image;
Params();
};
protected:
LLIconCtrl(const Params&);
friend class LLUICtrlFactory;
void setValue(const LLSD& value, S32 priority);
public:
virtual ~LLIconCtrl();
// llview overrides
virtual void draw();
// llview overrides
virtual bool handleHover(S32 x, S32 y, MASK mask);
// lluictrl overrides
void onVisibilityChange(bool new_visibility);
virtual void setValue(const LLSD& value );
std::string getImageName() const;
void setColor(const LLUIColor& color) { mColor = color; }
void setImage(LLPointer<LLUIImage> image) { mImagep = image; }
const LLPointer<LLUIImage> getImage() { return mImagep; }
protected:
S32 mPriority;
//the output size of the icon image if set.
S32 mMinWidth,
mMinHeight,
mMaxWidth,
mMaxHeight;
// If set to true (default), use the draw context transparency.
// If false, will use transparency returned by getCurrentTransparency(). See STORM-698.
bool mUseDrawContextAlpha;
bool mInteractable;
private:
void loadImage(const LLSD& value, S32 priority);
LLUIColor mColor;
LLPointer<LLUIImage> mImagep;
};
#endif
File diff suppressed because it is too large Load Diff
+214
View File
@@ -0,0 +1,214 @@
/**
* @file llkeywords.h
* @brief Keyword list for LSL
*
* $LicenseInfo:firstyear=2001&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_LLKEYWORDS_H
#define LL_LLKEYWORDS_H
#include "lldir.h"
#include "llstyle.h"
#include "llstring.h"
#include "v3color.h"
#include "v4color.h"
#include <map>
#include <list>
#include <deque>
#include "llpointer.h"
// <FS:Ansariel> Script editor ignoring font selection
class LLStyle;
typedef LLPointer<LLStyle> LLStyleSP;
// </FS:Ansariel
class LLTextSegment;
typedef LLPointer<LLTextSegment> LLTextSegmentPtr;
class LLKeywordToken
{
public:
/**
* @brief Types of tokens/delimters being parsed.
*
* @desc Tokens/delimiters that need to be identified/highlighted. All are terminated if an EOF is encountered.
* - TT_WORD are keywords in the normal sense, i.e. constants, events, etc.
* - TT_LINE are for entire lines (currently only flow control labels use this).
* - TT_ONE_SIDED_DELIMITER are for open-ended delimiters which are terminated by EOL.
* - TT_TWO_SIDED_DELIMITER are for delimiters that end with a different delimiter than they open with.
* - TT_DOUBLE_QUOTATION_MARKS are for delimiting areas using the same delimiter to open and close.
*/
typedef enum e_token_type
{
TT_UNKNOWN,
TT_WORD,
TT_LINE,
TT_TWO_SIDED_DELIMITER,
TT_ONE_SIDED_DELIMITER,
TT_DOUBLE_QUOTATION_MARKS,
// Following constants are more specific versions of the preceding ones
TT_CONSTANT, // WORD
TT_CONTROL, // WORD
TT_EVENT, // WORD
TT_FUNCTION, // WORD
TT_LABEL, // LINE
TT_SECTION, // WORD
TT_TYPE // WORD
} ETokenType;
LLKeywordToken( ETokenType type, const LLUIColor& color, const LLWString& token, const LLWString& tool_tip, const LLWString& delimiter )
:
mType( type ),
mToken( token ),
mColor( color ),
mToolTip( tool_tip ),
mDelimiter( delimiter ) // right delimiter
{
}
S32 getLengthHead() const { return static_cast<S32>(mToken.size()); }
S32 getLengthTail() const { return static_cast<S32>(mDelimiter.size()); }
bool isHead(const llwchar* s) const;
bool isTail(const llwchar* s) const;
const LLWString& getToken() const { return mToken; }
const LLUIColor& getColor() const { return mColor; }
ETokenType getType() const { return mType; }
const LLWString& getToolTip() const { return mToolTip; }
const LLWString& getDelimiter() const { return mDelimiter; }
#ifdef _DEBUG
void dump();
#endif
private:
ETokenType mType;
LLWString mToken;
LLUIColor mColor;
LLWString mToolTip;
LLWString mDelimiter;
};
class LLKeywords
{
public:
LLKeywords();
~LLKeywords();
void clearLoaded() { mLoaded = false; }
LLUIColor getColorGroup(std::string_view key_in);
bool isLoaded() const { return mLoaded; }
// <FS:Ansariel> Re-add support for Cinder's legacy file format
bool loadFromLegacyFile(const std::string& filename);
void findSegments(std::vector<LLTextSegmentPtr> *seg_list,
const LLWString& text,
class LLTextEditor& editor,
LLStyleConstSP style);
void initialize(LLSD SyntaxXML);
void processTokens();
// Add the token as described
void addToken(LLKeywordToken::ETokenType type,
const std::string& key,
const LLUIColor& color,
const std::string& tool_tip = LLStringUtil::null,
const std::string& delimiter = LLStringUtil::null);
// This class is here as a performance optimization.
// The word token map used to be defined as std::map<LLWString, LLKeywordToken*>.
// This worked, but caused a performance bottleneck due to memory allocation and string copies
// because it's not possible to search such a map without creating an LLWString.
// Using this class as the map index instead allows us to search using segments of an existing
// text run without copying them first, which greatly reduces overhead in LLKeywords::findSegments().
class WStringMapIndex
{
public:
// copy constructor
WStringMapIndex(const WStringMapIndex& other);
// constructor from a string (copies the string's data into the new object)
WStringMapIndex(const LLWString& str);
// constructor from pointer and length
// NOTE: does NOT copy data, caller must ensure that the lifetime of the pointer exceeds that of the new object!
WStringMapIndex(const llwchar *start, size_t length);
~WStringMapIndex();
bool operator<(const WStringMapIndex &other) const;
private:
void copyData(const llwchar *start, size_t length);
const llwchar *mData;
size_t mLength;
bool mOwner;
LLUIColor mColor;
};
typedef std::map<WStringMapIndex, LLKeywordToken*> word_token_map_t;
typedef word_token_map_t::const_iterator keyword_iterator_t;
keyword_iterator_t begin() const { return mWordTokenMap.begin(); }
keyword_iterator_t end() const { return mWordTokenMap.end(); }
typedef std::map<WStringMapIndex, LLUIColor> group_color_map_t;
typedef group_color_map_t::const_iterator color_iterator_t;
group_color_map_t mColorGroupMap;
#ifdef _DEBUG
void dump();
#endif
protected:
void processTokensGroup(const LLSD& Tokens, std::string_view Group);
void insertSegment(std::vector<LLTextSegmentPtr>& seg_list,
LLTextSegmentPtr new_segment,
S32 text_len,
const LLUIColor &defaultColor,
class LLTextEditor& editor);
void insertSegments(const LLWString& wtext,
std::vector<LLTextSegmentPtr>& seg_list,
LLKeywordToken* token,
S32 text_len,
S32 seg_start,
S32 seg_end,
LLStyleConstSP style,
LLTextEditor& editor);
void insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSegmentPtr new_segment, S32 text_len, LLStyleConstSP style, LLTextEditor& editor );
bool mLoaded;
LLSD mSyntax;
word_token_map_t mWordTokenMap;
typedef std::deque<LLKeywordToken*> token_list_t;
token_list_t mLineTokenList;
token_list_t mDelimiterTokenList;
typedef std::map<std::string, std::string, std::less<>> element_attributes_t;
typedef element_attributes_t::const_iterator attribute_iterator_t;
element_attributes_t mAttributes;
std::string getAttribute(std::string_view key);
std::string getArguments(LLSD& arguments);
// <FS:Ansariel> Script editor ignoring font selection
LLStyleSP getDefaultStyle(const LLTextEditor& editor);
};
#endif // LL_LLKEYWORDS_H
File diff suppressed because it is too large Load Diff
+238
View File
@@ -0,0 +1,238 @@
/**
* @file lllayoutstack.h
* @author Richard Nelson
* @brief LLLayout class - dynamic stacking of UI elements
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Reshasearch, 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_LLLAYOUTSTACK_H
#define LL_LLLAYOUTSTACK_H
#include "llpanel.h"
#include "llresizebar.h"
class LLLayoutPanel;
class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
{
public:
struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry>
{
LLSINGLETON_EMPTY_CTOR(LayoutStackRegistry);
};
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
Mandatory<EOrientation> orientation;
Optional<S32> border_size;
Optional<bool> animate,
clip;
Optional<F32> open_time_constant,
close_time_constant;
Optional<S32> resize_bar_overlap;
Optional<bool> show_drag_handle;
Optional<S32> drag_handle_first_indent;
Optional<S32> drag_handle_second_indent;
Optional<S32> drag_handle_thickness;
Optional<S32> drag_handle_shift;
Optional<LLUIColor> drag_handle_color;
// <FS:Zi> Add size save control. Caveat: contained panels and widgets need to use
// relative sizing, like right="-1" instead of width="XYZ" to get resized
// properly when a saved size is being restored. -Zi
Optional<bool> save_sizes;
Params();
};
typedef LayoutStackRegistry child_registry_t;
virtual ~LLLayoutStack();
/*virtual*/ void draw();
/*virtual*/ void deleteAllChildren();
/*virtual*/ void removeChild(LLView*);
/*virtual*/ bool postBuild();
/*virtual*/ bool addChild(LLView* child, S32 tab_group = 0);
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true);
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
typedef enum e_animate
{
NO_ANIMATE,
ANIMATE
} EAnimate;
void addPanel(LLLayoutPanel* panel, EAnimate animate = NO_ANIMATE);
void collapsePanel(LLPanel* panel, bool collapsed = true);
S32 getNumPanels() { return static_cast<S32>(mPanels.size()); }
void updateLayout();
S32 getPanelSpacing() const { return mPanelSpacing; }
void setPanelSpacing(S32 val);
static void updateClass();
// <FS:Ansariel> Applier for dimensions
void refreshFromSettings();
protected:
LLLayoutStack(const Params&);
friend class LLUICtrlFactory;
friend class LLLayoutPanel;
private:
void updateResizeBarLimits();
bool animatePanels();
void createResizeBar(LLLayoutPanel* panel);
const EOrientation mOrientation;
typedef std::vector<LLLayoutPanel*> e_panel_list_t;
e_panel_list_t mPanels;
LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
LLLayoutPanel* findEmbeddedPanelByName(std::string_view name) const;
void updateFractionalSizes();
void normalizeFractionalSizes();
void updatePanelRect( LLLayoutPanel* param1, const LLRect& new_rect );
S32 mPanelSpacing;
// true if we already applied animation this frame
bool mAnimatedThisFrame;
bool mAnimate;
bool mClip;
F32 mOpenTimeConstant;
F32 mCloseTimeConstant;
bool mNeedsLayout;
S32 mResizeBarOverlap;
bool mShowDragHandle;
S32 mDragHandleFirstIndent;
S32 mDragHandleSecondIndent;
S32 mDragHandleThickness;
S32 mDragHandleShift;
LLUIColor mDragHandleColor;
// <FS:Zi> Save sizes of the layout stack panels
const bool mSaveSizes;
std::string mSizeControlName;
LLSD mSavedSizes;
// </FS:Zi>
}; // end class LLLayoutStack
class LLLayoutPanel : public LLPanel
{
friend class LLLayoutStack;
friend class LLUICtrlFactory;
public:
struct Params : public LLInitParam::Block<Params, LLPanel::Params>
{
Optional<S32> expanded_min_dim,
min_dim;
Optional<bool> user_resize,
auto_resize;
Params();
};
~LLLayoutPanel();
void initFromParams(const Params& p);
void handleReshape(const LLRect& new_rect, bool by_user);
void reshape(S32 width, S32 height, bool called_from_parent = true);
void setVisible(bool visible);
S32 getLayoutDim() const;
S32 getTargetDim() const;
void setTargetDim(S32 value);
S32 getMinDim() const { return llmax(0, mMinDim); }
void setMinDim(S32 value) { mMinDim = value; }
S32 getExpandedMinDim() const { return mExpandedMinDim >= 0 ? mExpandedMinDim : getMinDim(); }
void setExpandedMinDim(S32 value) { mExpandedMinDim = value; }
S32 getRelevantMinDim() const
{
S32 min_dim = mMinDim;
if (!mCollapsed)
{
min_dim = getExpandedMinDim();
}
return min_dim;
}
F32 getAutoResizeFactor() const;
F32 getVisibleAmount() const;
S32 getVisibleDim() const;
LLResizeBar* getResizeBar() { return mResizeBar; }
bool isCollapsed() const { return mCollapsed;}
void setOrientation(LLView::EOrientation orientation);
void storeOriginalDim();
void setIgnoreReshape(bool ignore) { mIgnoreReshape = ignore; }
// <FS:Ansariel> Add callback for reshaping
typedef boost::function<void(LLLayoutPanel* panel, const LLRect& rect)> reshape_panel_callback_t;
void setReshapePanelCallback(reshape_panel_callback_t cb) { mReshapePanelCallback = cb; }
// </FS:Ansariel>
protected:
LLLayoutPanel(const Params& p);
const bool mAutoResize;
const bool mUserResize;
S32 mExpandedMinDim;
S32 mMinDim;
bool mCollapsed;
F32 mVisibleAmt;
F32 mCollapseAmt;
F32 mFractionalSize;
S32 mTargetDim;
bool mIgnoreReshape;
LLView::EOrientation mOrientation;
class LLResizeBar* mResizeBar;
// <FS:Ansariel> Add callback for reshaping
reshape_panel_callback_t mReshapePanelCallback;
};
#endif
+82
View File
@@ -0,0 +1,82 @@
/**
* @file lllazyvalue.h
* @brief generic functor/value abstraction for lazy evaluation of a value
* parsing construction parameters from xml and LLSD
*
* $LicenseInfo:firstyear=2008&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_LAZY_VALUE_H
#define LL_LAZY_VALUE_H
#include <boost/function.hpp>
// Holds on to a value of type T *or* calls a functor to generate a value of type T
template<typename T>
class LLLazyValue
{
public:
typedef typename boost::add_reference<typename boost::add_const<T>::type>::type T_const_ref;
typedef typename boost::function<T_const_ref (void)> function_type;
public:
LLLazyValue(const function_type& value)
: mValueGetter(value)
{}
LLLazyValue(T_const_ref value)
: mValue(value)
{}
LLLazyValue()
: mValue()
{}
void set(const LLLazyValue& val)
{
mValueGetter = val.mValueGetter;
}
void set(T_const_ref val)
{
mValue = val;
mValueGetter = NULL;
}
T_const_ref get() const
{
if (!mValueGetter.empty())
{
return mValueGetter();
}
return mValue;
}
bool isUsingFunction() const
{
return mValueGetter != NULL;
}
private:
function_type mValueGetter;
T mValue;
};
#endif // LL_LAZY_VALUE_H
File diff suppressed because it is too large Load Diff
+494
View File
@@ -0,0 +1,494 @@
/**
* @file lllineeditor.h
* @brief Text editor widget to let users enter/edit a single line.
*
* Features:
* Text entry of a single line (text, delete, left and right arrow, insert, return).
* Callbacks either on every keystroke or just on the return key.
* Focus (allow multiple text entry widgets)
* Clipboard (cut, copy, and paste)
* Horizontal scrolling to allow strings longer than widget size allows
* Pre-validation (limit which keys can be used)
* Optional line history so previous entries can be recalled by CTRL UP/DOWN
*
* $LicenseInfo:firstyear=2001&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_LLLINEEDITOR_H
#define LL_LLLINEEDITOR_H
#include "v4color.h"
#include "llframetimer.h"
#include "lleditmenuhandler.h"
#include "llfontvertexbuffer.h"
#include "llspellcheckmenuhandler.h"
#include "lluictrl.h"
#include "lluiimage.h"
#include "lluistring.h"
#include "llviewborder.h"
#include "llpreeditor.h"
#include "lltextvalidate.h"
class LLFontGL;
class LLLineEditorRollback;
class LLButton;
class LLContextMenu;
class LLLineEditor
: public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor, public LLSpellCheckMenuHandler
{
public:
typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t;
struct MaxLength : public LLInitParam::ChoiceBlock<MaxLength>
{
Alternative<S32> bytes, chars;
MaxLength() : bytes("max_length_bytes", 4096), // FS:TM needs to be this big for fields like entering in full path location to files on the local computer
chars("max_length_chars", 0)
{}
};
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<std::string> default_text;
Optional<MaxLength> max_length;
Optional<keystroke_callback_t> keystroke_callback;
Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator;
Optional<LLTextValidate::Validator, LLTextValidate::Validators> input_prevalidator;
Optional<LLViewBorder::Params> border;
Optional<LLUIImage*> background_image,
background_image_disabled,
background_image_focused;
Optional<bool> select_on_focus,
revert_on_esc,
spellcheck,
commit_on_focus_lost,
ignore_tab,
bg_image_always_focused,
show_label_focused,
is_password,
allow_emoji,
use_bg_color;
// colors
Optional<LLUIColor> cursor_color,
bg_color,
text_color,
text_readonly_color,
text_tentative_color,
highlight_color,
preedit_bg_color;
Optional<S32> text_pad_left,
text_pad_right;
Ignored bg_visible;
Params();
};
void initFromParams(const LLLineEditor::Params& params);
protected:
LLLineEditor(const Params&);
friend class LLUICtrlFactory;
friend class LLFloaterEditUI;
// <FS:Ansariel> FIRE-19933: Open context menu on context menu key press
//void showContextMenu(S32 x, S32 y);
void showContextMenu(S32 x, S32 y, bool set_cursor_pos = true);
// </FS:Ansariel>
public:
virtual ~LLLineEditor();
// mousehandler overrides
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleDoubleClick(S32 x,S32 y,MASK mask) override;
/*virtual*/ bool handleMiddleMouseDown(S32 x,S32 y,MASK mask) override;
/*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleKeyHere(KEY key, MASK mask) override;
/*virtual*/ bool handleUnicodeCharHere(llwchar uni_char) override;
/*virtual*/ void onMouseCaptureLost() override;
// LLEditMenuHandler overrides
/*virtual*/ void cut() override;
/*virtual*/ bool canCut() const override;
/*virtual*/ void copy() override;
/*virtual*/ bool canCopy() const override;
/*virtual*/ void paste() override;
/*virtual*/ bool canPaste() const override;
virtual void updatePrimary();
virtual void copyPrimary();
virtual void pastePrimary();
virtual bool canPastePrimary() const;
/*virtual*/ void doDelete() override;
/*virtual*/ bool canDoDelete() const override;
/*virtual*/ void selectAll() override;
/*virtual*/ bool canSelectAll() const override;
/*virtual*/ void deselect() override;
/*virtual*/ bool canDeselect() const override;
// LLSpellCheckMenuHandler overrides
/*virtual*/ bool getSpellCheck() const override;
/*virtual*/ const std::string& getSuggestion(U32 index) const override;
/*virtual*/ U32 getSuggestionCount() const override;
/*virtual*/ void replaceWithSuggestion(U32 index) override;
/*virtual*/ void addToDictionary() override;
/*virtual*/ bool canAddToDictionary() const override;
/*virtual*/ void addToIgnore() override;
/*virtual*/ bool canAddToIgnore() const override;
// Spell checking helper functions
std::string getMisspelledWord(U32 pos) const;
bool isMisspelledWord(U32 pos) const;
void onSpellCheckSettingsChange();
// view overrides
/*virtual*/ void draw() override;
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true) override;
/*virtual*/ void onFocusReceived() override;
/*virtual*/ void onFocusLost() override;
/*virtual*/ void setEnabled(bool enabled) override;
// UI control overrides
/*virtual*/ void clear() override;
/*virtual*/ void onTabInto() override;
/*virtual*/ void setFocus(bool b) override;
/*virtual*/ void setRect(const LLRect& rect) override;
/*virtual*/ bool acceptsTextInput() const override;
/*virtual*/ void onCommit() override;
/*virtual*/ bool isDirty() const override; // Returns true if user changed value at all
/*virtual*/ void resetDirty() override; // Clear dirty state
// assumes UTF8 text
/*virtual*/ void setValue(const LLSD& value) override;
/*virtual*/ LLSD getValue() const override;
/*virtual*/ bool setTextArg(const std::string& key, const LLStringExplicit& text) override;
/*virtual*/ bool setLabelArg(const std::string& key, const LLStringExplicit& text) override;
//<FS:TS> FIRE-11373: Autoreplace doesn't work in nearby chat bar
typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t;
autoreplace_callback_t mAutoreplaceCallback;
void setAutoreplaceCallback (autoreplace_callback_t cb) { mAutoreplaceCallback = cb; }
//</FS:TS> FIRE-11373
void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; }
const std::string& getLabel() { return mLabel.getString(); }
void setText(const LLStringExplicit &new_text);
const std::string& getText() const override { return mText.getString(); }
const LLWString& getWText() const { return mText.getWString(); }
LLWString getConvertedText() const; // trimmed text with paragraphs converted to newlines
S32 getLength() const { return mText.length(); }
S32 getCursor() const { return mCursorPos; }
void setCursor( S32 pos );
void setCursorToEnd();
// set scroll to earliest position it can reasonable set
void resetScrollPosition();
// Selects characters 'start' to 'end'.
void setSelection(S32 start, S32 end);
/*virtual*/ void getSelectionRange(S32 *position, S32 *length) const override;
void setCommitOnFocusLost( bool b ) { mCommitOnFocusLost = b; }
void setRevertOnEsc( bool b ) { mRevertOnEsc = b; }
void setKeystrokeOnEsc(bool b) { mKeystrokeOnEsc = b; }
void setCursorColor(const LLUIColor& c) { mCursorColor = c; }
const LLColor4& getCursorColor() const { return mCursorColor.get(); }
void setFgColor( const LLUIColor& c ) { mFgColor = c; }
void setReadOnlyFgColor( const LLUIColor& c ) { mReadOnlyFgColor = c; }
void setTentativeFgColor(const LLUIColor& c) { mTentativeFgColor = c; }
const LLColor4& getFgColor() const { return mFgColor.get(); }
const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor.get(); }
const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); }
const LLFontGL* getFont() const override { return mGLFont; }
void setFont(const LLFontGL* font);
void setIgnoreArrowKeys(bool b) { mIgnoreArrowKeys = b; }
void setIgnoreTab(bool b) { mIgnoreTab = b; }
void setPassDelete(bool b) { mPassDelete = b; }
void setAllowEmoji(bool b) { mAllowEmoji = b; }
void setDrawAsterixes(bool b);
// get the cursor position of the beginning/end of the prev/next word in the text
S32 prevWordPos(S32 cursorPos) const;
S32 nextWordPos(S32 cursorPos) const;
bool hasSelection() const { return (mSelectionStart != mSelectionEnd); }
void startSelection();
void endSelection();
void extendSelection(S32 new_cursor_pos);
void deleteSelection();
void setSelectAllonFocusReceived(bool b);
void setSelectAllonCommit(bool b) { mSelectAllonCommit = b; }
void onKeystroke();
typedef boost::function<void (LLLineEditor* caller, void* user_data)> callback_t;
void setKeystrokeCallback(callback_t callback, void* user_data);
void setMaxTextLength(S32 max_text_length);
void setMaxTextChars(S32 max_text_chars);
// Manipulate left and right padding for text
void getTextPadding(S32 *left, S32 *right);
void setTextPadding(S32 left, S32 right);
// Prevalidation controls which keystrokes can affect the editor
void setPrevalidate(LLTextValidate::Validator validator);
// This method sets callback that prevents from:
// - deleting, selecting, typing, cutting, pasting characters that are not valid.
// Also callback that this method sets differs from setPrevalidate in a way that it validates just inputed
// symbols, before existing text is modified, but setPrevalidate validates line after it was modified.
void setPrevalidateInput(LLTextValidate::Validator validator);
static bool postvalidateFloat(const std::string &str);
bool prevalidateInput(const LLWString& wstr);
bool evaluateFloat();
// line history support:
void setEnableLineHistory( bool enabled ) { mHaveHistory = enabled; } // switches line history on or off
void updateHistory(); // stores current line in history
void setReplaceNewlinesWithSpaces(bool replace);
void resetContextMenu() { setContextMenu(NULL); };
void setBgImage(LLPointer<LLUIImage> image) { mBgImage = image; }
void setBgImageFocused(LLPointer<LLUIImage> image) { mBgImageFocused = image; }
void setShowContextMenu(bool show) { mShowContextMenu = show; }
bool getShowContextMenu() const { return mShowContextMenu; }
// <FS:Ansariel> Make these protected
void removeChar();
void removeWord(bool prev);
void addChar(const llwchar c);
// </FS:Ansariel>
private:
// private helper methods
void pasteHelper(bool is_primary);
// <FS:Ansariel> Make these protected
//void removeChar();
//void addChar(const llwchar c);
// </FS:Ansariel>
void setCursorAtLocalPos(S32 local_mouse_x);
S32 findPixelNearestPos(S32 cursor_offset = 0) const;
S32 calcCursorPos(S32 mouse_x);
bool handleSpecialKey(KEY key, MASK mask);
bool handleSelectionKey(KEY key, MASK mask);
bool handleControlKey(KEY key, MASK mask);
S32 handleCommitKey(KEY key, MASK mask);
void updateTextPadding();
// Draw the background image depending on enabled/focused state.
void drawBackground();
//
// private data members
//
void updateAllowingLanguageInput();
bool hasPreeditString() const;
// Implementation (overrides) of LLPreeditor
/*virtual*/ void resetPreedit() override;
/*virtual*/ void updatePreedit(const LLWString &preedit_string,
const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) override;
/*virtual*/ void markAsPreedit(S32 position, S32 length) override;
/*virtual*/ void getPreeditRange(S32 *position, S32 *length) const override;
/*virtual*/ bool getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const override;
/*virtual*/ S32 getPreeditFontSize() const override;
/*virtual*/ LLWString getPreeditString() const override { return getWText(); }
void setText(const LLStringExplicit &new_text, bool use_size_limit);
void setContextMenu(LLContextMenu* new_context_menu);
protected:
LLUIString mText; // The string being edited.
std::string mPrevText; // Saved string for 'ESC' revert
LLUIString mLabel; // text label that is visible when no user text provided
// line history support:
bool mHaveHistory; // flag for enabled line history
typedef std::vector<std::string> line_history_t;
line_history_t mLineHistory; // line history storage
line_history_t::iterator mCurrentHistoryLine; // currently browsed history line
LLViewBorder* mBorder;
const LLFontGL* mGLFont;
LLFontVertexBuffer mFontBufferPreSelection;
LLFontVertexBuffer mFontBufferSelection;
LLFontVertexBuffer mFontBufferPostSelection;
LLFontVertexBuffer mFontBufferLabel;
S32 mMaxLengthBytes; // Max length of the UTF8 string in bytes
S32 mMaxLengthChars; // Maximum number of characters in the string
S32 mCursorPos; // I-beam is just after the mCursorPos-th character.
S32 mScrollHPos; // Horizontal offset from the start of mText. Used for scrolling.
LLFrameTimer mScrollTimer;
S32 mTextPadLeft; // Used to reserve space before the beginning of the text for children.
S32 mTextPadRight; // Used to reserve space after the end of the text for children.
S32 mTextLeftEdge; // Pixels, cached left edge of text based on left padding and width
S32 mTextRightEdge; // Pixels, cached right edge of text based on right padding and width
bool mCommitOnFocusLost;
bool mRevertOnEsc;
bool mKeystrokeOnEsc;
keystroke_callback_t mKeystrokeCallback;
bool mIsSelecting; // Selection for clipboard operations
S32 mSelectionStart;
S32 mSelectionEnd;
S32 mLastSelectionX;
S32 mLastSelectionY;
S32 mLastSelectionStart;
S32 mLastSelectionEnd;
bool mSpellCheck;
S32 mSpellCheckStart;
S32 mSpellCheckEnd;
LLTimer mSpellCheckTimer;
std::list<std::pair<U32, U32> > mMisspellRanges;
std::vector<std::string> mSuggestionList;
LLTextValidate::Validator mPrevalidator;
LLTextValidate::Validator mInputPrevalidator;
LLFrameTimer mKeystrokeTimer;
LLTimer mTripleClickTimer;
LLUIColor mCursorColor;
LLUIColor mBgColor;
LLUIColor mFgColor;
LLUIColor mReadOnlyFgColor;
LLUIColor mTentativeFgColor;
LLUIColor mHighlightColor; // background for selected text
LLUIColor mPreeditBgColor; // preedit marker background color
S32 mBorderThickness;
bool mIgnoreArrowKeys;
bool mIgnoreTab;
bool mDrawAsterixes;
bool mSelectAllonFocusReceived;
bool mSelectAllonCommit;
bool mPassDelete;
bool mReadOnly;
bool mShowImageFocused;
bool mShowLabelFocused;
bool mAllowEmoji;
bool mUseBgColor;
LLWString mPreeditWString;
LLWString mPreeditOverwrittenWString;
std::vector<S32> mPreeditPositions;
LLPreeditor::standouts_t mPreeditStandouts;
LLHandle<LLContextMenu> mContextMenuHandle;
bool mShowContextMenu;
private:
// Instances that by default point to the statics but can be overidden in XML.
LLPointer<LLUIImage> mBgImage;
LLPointer<LLUIImage> mBgImageDisabled;
LLPointer<LLUIImage> mBgImageFocused;
bool mReplaceNewlinesWithSpaces; // if false, will replace pasted newlines with paragraph symbol.
// private helper class
class LLLineEditorRollback
{
public:
LLLineEditorRollback( LLLineEditor* ed )
:
mCursorPos( ed->mCursorPos ),
mScrollHPos( ed->mScrollHPos ),
mIsSelecting( ed->mIsSelecting ),
mSelectionStart( ed->mSelectionStart ),
mSelectionEnd( ed->mSelectionEnd )
{
mText = ed->getText();
}
void doRollback( LLLineEditor* ed )
{
ed->mCursorPos = mCursorPos;
ed->mScrollHPos = mScrollHPos;
ed->mIsSelecting = mIsSelecting;
ed->mSelectionStart = mSelectionStart;
ed->mSelectionEnd = mSelectionEnd;
ed->mText = mText;
ed->mPrevText = mText;
}
std::string getText() { return mText; }
private:
std::string mText;
S32 mCursorPos;
S32 mScrollHPos;
bool mIsSelecting;
S32 mSelectionStart;
S32 mSelectionEnd;
}; // end class LLLineEditorRollback
}; // end class LLLineEditor
// Build time optimization, generate once in .cpp file
#ifndef LLLINEEDITOR_CPP
extern template class LLLineEditor* LLView::getChild<class LLLineEditor>(
std::string_view name, bool recurse) const;
#endif
#endif // LL_LINEEDITOR_
+99
View File
@@ -0,0 +1,99 @@
/**
* @file llloadingindicator.cpp
* @brief Perpetual loading indicator
*
* $LicenseInfo:firstyear=2010&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$
*/
#include "linden_common.h"
#include "llloadingindicator.h"
// Linden library includes
#include "llsingleton.h"
// Project includes
#include "lluictrlfactory.h"
#include "lluiimage.h"
// registered in llui.cpp to avoid being left out by MS linker
//static LLDefaultChildRegistry::Register<LLLoadingIndicator> r("loading_indicator");
///////////////////////////////////////////////////////////////////////////////
// LLLoadingIndicator class
///////////////////////////////////////////////////////////////////////////////
LLLoadingIndicator::LLLoadingIndicator(const Params& p)
: LLUICtrl(p),
mImagesPerSec(p.images_per_sec > 0 ? p.images_per_sec : 1.0f),
mCurImageIdx(0)
{
}
void LLLoadingIndicator::initFromParams(const Params& p)
{
for (LLUIImage* image : p.images().image)
{
mImages.push_back(image);
}
// Start timer for switching images.
start();
}
void LLLoadingIndicator::draw()
{
// Time to switch to the next image?
if (mImageSwitchTimer.getStarted() && mImageSwitchTimer.hasExpired())
{
// Switch to the next image.
if (!mImages.empty())
{
mCurImageIdx = (mCurImageIdx + 1) % mImages.size();
}
// Restart timer.
start();
}
LLUIImagePtr cur_image = mImages.empty() ? LLUIImagePtr(NULL) : mImages[mCurImageIdx];
// Draw current image.
if( cur_image.notNull() )
{
cur_image->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha);
}
LLUICtrl::draw();
}
void LLLoadingIndicator::stop()
{
mImageSwitchTimer.stop();
}
void LLLoadingIndicator::start()
{
mImageSwitchTimer.start();
F32 period = 1.0f / (mImages.size() * mImagesPerSec);
mImageSwitchTimer.setTimerExpirySec(period);
}
+104
View File
@@ -0,0 +1,104 @@
/**
* @file llloadingindicator.h
* @brief Perpetual loading indicator
*
* $LicenseInfo:firstyear=2010&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_LLLOADINGINDICATOR_H
#define LL_LLLOADINGINDICATOR_H
#include "lluictrl.h"
#include "lluiimage.h"
///////////////////////////////////////////////////////////////////////////////
// class LLLoadingIndicator
///////////////////////////////////////////////////////////////////////////////
/**
* Perpetual loading indicator (a la MacOSX or YouTube)
*
* Number of rotations per second can be overridden
* with the "images_per_sec" parameter.
*
* Can start/stop spinning.
*
* @see start()
* @see stop()
*/
class LLLoadingIndicator
: public LLUICtrl
{
LOG_CLASS(LLLoadingIndicator);
public:
struct Images : public LLInitParam::Block<Images>
{
Multiple<LLUIImage*> image;
Images()
: image("image")
{}
};
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<F32> images_per_sec;
Optional<Atomic<Images> > images;
Params()
: images_per_sec("images_per_sec", 1.0f),
images("images")
{}
};
virtual ~LLLoadingIndicator() {}
// llview overrides
virtual void draw();
/**
* Stop spinning.
*/
void stop();
/**
* Start spinning.
*/
void start();
void reset() { mCurImageIdx = 0; }
private:
LLLoadingIndicator(const Params&);
void initFromParams(const Params&);
friend class LLUICtrlFactory;
F32 mImagesPerSec;
S8 mCurImageIdx;
LLFrameTimer mImageSwitchTimer;
std::vector<LLUIImagePtr> mImages;
};
#endif // LL_LLLOADINGINDICATOR_H
+110
View File
@@ -0,0 +1,110 @@
/**
* @file lllocalcliprect.cpp
*
* $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$
*/
#include "linden_common.h"
#include "lllocalcliprect.h"
#include "llfontgl.h"
#include "llui.h"
/*static*/ std::stack<LLRect> LLScreenClipRect::sClipRectStack;
LLScreenClipRect::LLScreenClipRect(const LLRect& rect, bool enabled)
: mScissorState(GL_SCISSOR_TEST),
mEnabled(enabled)
{
if (mEnabled)
{
pushClipRect(rect);
mScissorState.setEnabled(!sClipRectStack.empty());
updateScissorRegion();
}
}
LLScreenClipRect::~LLScreenClipRect()
{
if (mEnabled)
{
popClipRect();
updateScissorRegion();
}
}
//static
void LLScreenClipRect::pushClipRect(const LLRect& rect)
{
LLRect combined_clip_rect = rect;
if (!sClipRectStack.empty())
{
LLRect top = sClipRectStack.top();
combined_clip_rect.intersectWith(top);
if(combined_clip_rect.isEmpty())
{
// avoid artifacts where zero area rects show up as lines
combined_clip_rect = LLRect::null;
}
}
sClipRectStack.push(combined_clip_rect);
}
//static
void LLScreenClipRect::popClipRect()
{
sClipRectStack.pop();
}
//static
void LLScreenClipRect::updateScissorRegion()
{
if (sClipRectStack.empty()) return;
// finish any deferred calls in the old clipping region
gGL.flush();
LLRect rect = sClipRectStack.top();
stop_glerror();
S32 x,y,w,h;
x = llfloor(rect.mLeft * LLUI::getScaleFactor().mV[VX]);
y = llfloor(rect.mBottom * LLUI::getScaleFactor().mV[VY]);
w = llmax(0, llceil(rect.getWidth() * LLUI::getScaleFactor().mV[VX])) + 1;
h = llmax(0, llceil(rect.getHeight() * LLUI::getScaleFactor().mV[VY])) + 1;
glScissor( x,y,w,h );
stop_glerror();
}
//---------------------------------------------------------------------------
// LLLocalClipRect
//---------------------------------------------------------------------------
LLLocalClipRect::LLLocalClipRect(const LLRect& rect, bool enabled /* = true */)
: LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX,
rect.mTop + LLFontGL::sCurOrigin.mY,
rect.mRight + LLFontGL::sCurOrigin.mX,
rect.mBottom + LLFontGL::sCurOrigin.mY), enabled)
{}
LLLocalClipRect::~LLLocalClipRect()
{}
+63
View File
@@ -0,0 +1,63 @@
/**
* @file lllocalcliprect.h
*
* $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 LLLOCALCLIPRECT_H
#define LLLOCALCLIPRECT_H
#include "llgl.h"
#include "llrect.h" // can't forward declare, it's templated
#include <stack>
// Clip rendering to a specific rectangle using GL scissor
// Just create one of these on the stack:
// {
// LLLocalClipRect(rect);
// draw();
// }
class LLScreenClipRect
{
public:
LLScreenClipRect(const LLRect& rect, bool enabled = true);
virtual ~LLScreenClipRect();
private:
static void pushClipRect(const LLRect& rect);
static void popClipRect();
static void updateScissorRegion();
private:
LLGLState mScissorState;
bool mEnabled;
static std::stack<LLRect> sClipRectStack;
};
class LLLocalClipRect : public LLScreenClipRect
{
public:
LLLocalClipRect(const LLRect& rect, bool enabled = true);
~LLLocalClipRect();
};
#endif
+246
View File
@@ -0,0 +1,246 @@
/**
* @file llbutton.cpp
* @brief LLButton base class
*
* $LicenseInfo:firstyear=2001&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$
*/
#include "linden_common.h"
#include "llmenubutton.h"
// Linden library includes
#include "lltoggleablemenu.h"
#include "llstring.h"
#include "v4color.h"
static LLDefaultChildRegistry::Register<LLMenuButton> r("menu_button");
void LLMenuButton::MenuPositions::declareValues()
{
declare("topleft", MP_TOP_LEFT);
declare("topright", MP_TOP_RIGHT);
declare("bottomleft", MP_BOTTOM_LEFT);
declare("bottomright", MP_BOTTOM_RIGHT);
}
LLMenuButton::Params::Params()
: menu_filename("menu_filename"),
position("menu_position", MP_BOTTOM_LEFT)
{
addSynonym(position, "position");
}
LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
: LLButton(p),
mIsMenuShown(false),
mMenuPosition(p.position),
mOwnMenu(false)
{
std::string menu_filename = p.menu_filename;
setMenu(menu_filename, mMenuPosition);
updateMenuOrigin();
}
LLMenuButton::~LLMenuButton()
{
cleanup();
}
boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
{
return LLUICtrl::setMouseDownCallback(cb);
}
void LLMenuButton::hideMenu()
{
LLToggleableMenu* menu = getMenu();
if (menu)
{
menu->setVisible(false);
}
}
LLToggleableMenu* LLMenuButton::getMenu()
{
return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
}
void LLMenuButton::setMenu(const std::string& menu_filename, EMenuPosition position /*MP_TOP_LEFT*/)
{
if (menu_filename.empty())
{
return;
}
llassert(LLMenuGL::sMenuContainer != NULL);
LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
if (!menu)
{
LL_WARNS() << "Error loading menu_button menu" << LL_ENDL;
return;
}
setMenu(menu, position, true);
}
void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/, bool take_ownership /*false*/)
{
if (!menu) return;
cleanup(); // destroy the previous memnu if we own it
mMenuHandle = menu->getHandle();
mMenuPosition = position;
mOwnMenu = take_ownership;
menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
}
bool LLMenuButton::handleKeyHere(KEY key, MASK mask )
{
if (!getMenu()) return false;
if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
{
// *HACK: We emit the mouse down signal to fire the callback bound to the
// menu emerging event before actually displaying the menu. See STORM-263.
LLUICtrl::handleMouseDown(-1, -1, MASK_NONE);
toggleMenu();
return true;
}
LLToggleableMenu* menu = getMenu();
if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
{
menu->setVisible(false);
return true;
}
return false;
}
bool LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
{
LLButton::handleMouseDown(x, y, mask);
toggleMenu();
return true;
}
void LLMenuButton::toggleMenu()
{
if (mValidateSignal && !(*mValidateSignal)(this, LLSD()))
{
return;
}
LLToggleableMenu* menu = getMenu();
if (!menu) return;
// Store the button rectangle to toggle menu visibility if a mouse event
// occurred inside or outside the button rect.
menu->setButtonRect(this);
if (!menu->toggleVisibility() && mIsMenuShown)
{
setForcePressedState(false);
mIsMenuShown = false;
}
else
{
menu->buildDrawLabels();
menu->arrangeAndClear();
menu->updateParent(LLMenuGL::sMenuContainer);
updateMenuOrigin();
LLMenuGL::showPopup(getParent(), menu, mX, mY);
setForcePressedState(true);
mIsMenuShown = true;
}
}
void LLMenuButton::updateMenuOrigin()
{
LLToggleableMenu* menu = getMenu();
if (!menu) return;
LLRect rect = getRect();
switch (mMenuPosition)
{
case MP_TOP_LEFT:
{
mX = rect.mLeft;
mY = rect.mTop + menu->getRect().getHeight();
break;
}
case MP_TOP_RIGHT:
{
const LLRect& menu_rect = menu->getRect();
mX = rect.mRight - menu_rect.getWidth();
mY = rect.mTop + menu_rect.getHeight();
break;
}
case MP_BOTTOM_LEFT:
{
mX = rect.mLeft;
mY = rect.mBottom;
break;
}
case MP_BOTTOM_RIGHT:
{
const LLRect& menu_rect = menu->getRect();
mX = rect.mRight - menu_rect.getWidth();
mY = rect.mBottom;
break;
}
}
}
void LLMenuButton::onMenuVisibilityChange(const LLSD& param)
{
bool new_visibility = param["visibility"].asBoolean();
bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean();
// Reset the button "pressed" state only if the menu is shown by this particular
// menu button (not any other control) and is not being closed by a click on the button.
if (!new_visibility && !is_closed_by_button_click && mIsMenuShown)
{
setForcePressedState(false);
mIsMenuShown = false;
}
}
void LLMenuButton::cleanup()
{
if (mMenuHandle.get() && mOwnMenu)
{
mMenuHandle.get()->die();
}
}
+101
View File
@@ -0,0 +1,101 @@
/**
* @file llbutton.h
* @brief Header for buttons
*
* $LicenseInfo:firstyear=2001&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_LLMENUBUTTON_H
#define LL_LLMENUBUTTON_H
#include "llbutton.h"
class LLToggleableMenu;
class LLMenuButton
: public LLButton
{
LOG_CLASS(LLMenuButton);
public:
typedef enum e_menu_position
{
MP_TOP_LEFT,
MP_TOP_RIGHT,
MP_BOTTOM_LEFT,
MP_BOTTOM_RIGHT
} EMenuPosition;
struct MenuPositions
: public LLInitParam::TypeValuesHelper<EMenuPosition, MenuPositions>
{
static void declareValues();
};
struct Params
: public LLInitParam::Block<Params, LLButton::Params>
{
// filename for it's toggleable menu
Optional<std::string> menu_filename;
Optional<EMenuPosition, MenuPositions> position;
Params();
};
boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb );
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleKeyHere(KEY key, MASK mask );
void hideMenu();
LLToggleableMenu* getMenu();
void setMenu(const std::string& menu_filename, EMenuPosition position = MP_TOP_LEFT);
void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT, bool take_ownership = false);
void setMenuPosition(EMenuPosition position) { mMenuPosition = position; }
protected:
friend class LLUICtrlFactory;
LLMenuButton(const Params&);
~LLMenuButton();
void toggleMenu();
void updateMenuOrigin();
void onMenuVisibilityChange(const LLSD& param);
private:
void cleanup();
LLHandle<LLView> mMenuHandle;
bool mIsMenuShown;
EMenuPosition mMenuPosition;
S32 mX;
S32 mY;
bool mOwnMenu; // true if we manage the menu lifetime
};
#endif // LL_LLMENUBUTTON_H
File diff suppressed because it is too large Load Diff
+987
View File
@@ -0,0 +1,987 @@
/**
* @file llmenugl.h
* @brief Declaration of the opengl based menu system.
*
* $LicenseInfo:firstyear=2001&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_LLMENUGL_H
#define LL_LLMENUGL_H
#include <list>
#include "llstring.h"
#include "v4color.h"
#include "llframetimer.h"
#include "llkeyboard.h"
#include "llfloater.h"
#include "lluistring.h"
#include "llview.h"
#include <boost/function.hpp>
extern S32 MENU_BAR_HEIGHT;
extern S32 MENU_BAR_WIDTH;
class LLMenuKeyboardBinding
{
public:
KEY mKey;
MASK mMask;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemGL
//
// The LLMenuItemGL represents a single menu item in a menu.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl
{
public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<std::string> shortcut;
Optional<std::string> shortcut_linux; // <FS> Remap shortcuts on Linux
Optional<KEY> jump_key;
Optional<bool> use_mac_ctrl,
allow_key_repeat;
Ignored rect,
left,
top,
right,
bottom,
width,
height,
bottom_delta,
left_delta;
Optional<LLUIColor> enabled_color,
disabled_color,
highlight_bg_color,
highlight_fg_color;
Params();
};
protected:
LLMenuItemGL(const Params&);
friend class LLUICtrlFactory;
public:
// LLView overrides
/*virtual*/ void onVisibilityChange(bool new_visibility);
/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleRightMouseUp(S32 x, S32 y, MASK mask);
// LLUICtrl overrides
/*virtual*/ void setValue(const LLSD& value);
/*virtual*/ LLSD getValue() const;
virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
virtual bool handleAcceleratorKey(KEY key, MASK mask);
LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); }
void setJumpKey(KEY key);
KEY getJumpKey() const { return mJumpKey; }
// set the font used by this item.
void setFont(const LLFontGL* font) { mFont = font; }
const LLFontGL* getFont() const { return mFont; }
// returns the height in pixels for the current font.
virtual U32 getNominalHeight( void ) const;
// Marks item as not needing space for check marks or accelerator keys
virtual void setBriefItem(bool brief);
virtual bool isBriefItem() const;
virtual bool addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp);
void setAllowKeyRepeat(bool allow) { mAllowKeyRepeat = allow; }
bool getAllowKeyRepeat() const { return mAllowKeyRepeat; }
// change the label
void setLabel( const LLStringExplicit& label ) { mLabel = label; }
std::string getLabel( void ) const { return mLabel.getString(); }
virtual bool setLabelArg( const std::string& key, const LLStringExplicit& text );
// Get the parent menu for this item
virtual class LLMenuGL* getMenu() const;
// returns the normal width of this control in pixels - this is
// used for calculating the widest item, as well as for horizontal
// arrangement.
virtual U32 getNominalWidth( void ) const;
// buildDrawLabel() - constructs the string used during the draw()
// function. This reduces the overall string manipulation, but can
// lead to visual errors if the state of the object changes
// without the knowledge of the menu item. For example, if a
// boolean being watched is changed outside of the menu item's
// onCommit() function, the draw buffer will not be updated and will
// reflect the wrong value. If this ever becomes an issue, there
// are ways to fix this.
// Returns the enabled state of the item.
virtual void buildDrawLabel( void );
// for branching menu items, bring sub menus up to root level of menu hierarchy
virtual void updateBranchParent( LLView* parentp ){};
virtual void onCommit( void );
virtual void setHighlight( bool highlight );
virtual bool getHighlight() const { return mHighlight; }
// determine if this represents an active sub-menu
virtual bool isActive( void ) const { return false; }
// determine if this represents an open sub-menu
virtual bool isOpen( void ) const { return false; }
virtual void setEnabledSubMenus(bool enable){};
// LLView Functionality
virtual bool handleKeyHere( KEY key, MASK mask );
virtual bool handleMouseDown( S32 x, S32 y, MASK mask );
virtual bool handleMouseUp( S32 x, S32 y, MASK mask );
virtual bool handleScrollWheel( S32 x, S32 y, S32 clicks );
virtual void onMouseEnter(S32 x, S32 y, MASK mask);
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
virtual void draw( void );
bool getHover() const { return mGotHover; }
void setDrawTextDisabled(bool disabled) { mDrawTextDisabled = disabled; }
bool getDrawTextDisabled() const { return mDrawTextDisabled; }
protected:
void setHover(bool hover) { mGotHover = hover; }
// This function appends the character string representation of
// the current accelerator key and mask to the provided string.
void appendAcceleratorString( std::string& st ) const;
virtual std::string _getSearchText() const
{
return mLabel.getString();
}
protected:
KEY mAcceleratorKey;
MASK mAcceleratorMask;
// mLabel contains the actual label specified by the user.
LLUIString mLabel;
// The draw labels contain some of the labels that we draw during
// the draw() routine. This optimizes away some of the string
// manipulation.
LLUIString mDrawBoolLabel;
LLUIString mDrawAccelLabel;
LLUIString mDrawBranchLabel;
LLUIColor mEnabledColor;
LLUIColor mDisabledColor;
LLUIColor mHighlightBackground;
LLUIColor mHighlightForeground;
bool mHighlight;
private:
// Keyboard and mouse variables
bool mAllowKeyRepeat;
bool mGotHover;
// If true, suppress normal space for check marks on the left and accelerator
// keys on the right.
bool mBriefItem;
// Font for this item
const LLFontGL* mFont;
bool mDrawTextDisabled;
KEY mJumpKey;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemSeparatorGL
//
// This class represents a separator.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuItemSeparatorGL : public LLMenuItemGL
{
public:
struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
{
Optional<EnableCallbackParam > on_visible;
Params();
};
LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params());
/*virtual*/ void draw( void );
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask);
virtual void buildDrawLabel();
/*virtual*/ U32 getNominalHeight( void ) const;
private:
enable_signal_t mVisibleSignal;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemCallGL
//
// The LLMenuItemCallerGL represents a single menu item in a menu that
// calls a user defined callback.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuItemCallGL : public LLMenuItemGL
{
public:
struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
{
Optional<EnableCallbackParam > on_enable;
Optional<CommitCallbackParam > on_click;
Optional<EnableCallbackParam > on_visible;
Params()
: on_enable("on_enable"),
on_click("on_click"),
on_visible("on_visible")
{}
};
protected:
LLMenuItemCallGL(const Params&);
friend class LLUICtrlFactory;
void updateEnabled( void );
void updateVisible( void );
public:
void initFromParams(const Params& p);
// called to rebuild the draw label
virtual void buildDrawLabel( void );
virtual void onCommit( void );
virtual bool handleAcceleratorKey(KEY key, MASK mask);
virtual bool handleKeyHere(KEY key, MASK mask);
//virtual void draw();
boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb )
{
return setCommitCallback(cb);
}
boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb )
{
return mEnableSignal.connect(cb);
}
private:
enable_signal_t mEnableSignal;
enable_signal_t mVisibleSignal;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemCheckGL
//
// The LLMenuItemCheckGL is an extension of the LLMenuItemCallGL
// class, by allowing another method to be specified which determines
// if the menu item should consider itself checked as true or not. Be
// careful that the provided callback is fast - it needs to be VERY
// EFFICIENT because it may need to be checked a lot.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuItemCheckGL
: public LLMenuItemCallGL
{
public:
struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params>
{
Optional<EnableCallbackParam > on_check;
Params()
: on_check("on_check")
{}
};
protected:
LLMenuItemCheckGL(const Params&);
friend class LLUICtrlFactory;
public:
void initFromParams(const Params& p);
virtual void onCommit( void );
virtual void setValue(const LLSD& value);
virtual LLSD getValue() const;
// called to rebuild the draw label
virtual void buildDrawLabel( void );
boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb )
{
return mCheckSignal.connect(cb);
}
private:
enable_signal_t mCheckSignal;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuGL
//
// The Menu class represents a normal rectangular menu somewhere on
// screen. A Menu can have menu items (described above) or sub-menus
// attached to it. Sub-menus are implemented via a specialized
// menu-item type known as a branch. Since it's easy to do wrong, I've
// taken the branch functionality out of public view, and encapsulate
// it in the appendMenu() method.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// child widget registry
struct MenuRegistry : public LLChildRegistry<MenuRegistry>
{
LLSINGLETON_EMPTY_CTOR(MenuRegistry);
};
class LLMenuGL
: public LLUICtrl
{
public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<KEY> jump_key;
Optional<bool> horizontal_layout,
can_tear_off,
drop_shadow,
bg_visible,
create_jump_keys,
keep_fixed_size,
scrollable;
Optional<U32> max_scrollable_items;
Optional<U32> preferred_width;
Optional<LLUIColor> bg_color;
Optional<S32> shortcut_pad;
Params()
: jump_key("jump_key", KEY_NONE),
horizontal_layout("horizontal_layout"),
can_tear_off("tear_off", false),
drop_shadow("drop_shadow", true),
bg_visible("bg_visible", true),
create_jump_keys("create_jump_keys", false),
keep_fixed_size("keep_fixed_size", false),
bg_color("bg_color", LLUIColorTable::instance().getColor( "MenuDefaultBgColor" )),
scrollable("scrollable", false),
max_scrollable_items("max_scrollable_items", U32_MAX),
preferred_width("preferred_width", U32_MAX),
shortcut_pad("shortcut_pad")
{
addSynonym(bg_visible, "opaque");
addSynonym(bg_color, "color");
addSynonym(can_tear_off, "can_tear_off");
}
};
// my valid children are contained in MenuRegistry
typedef MenuRegistry child_registry_t;
void initFromParams(const Params&);
// textual artwork which menugl-imitators may want to match
static const std::string BOOLEAN_TRUE_PREFIX;
static const std::string BRANCH_SUFFIX;
static const std::string ARROW_UP;
static const std::string ARROW_DOWN;
// for scrollable menus
typedef enum e_scrolling_direction
{
SD_UP = 0,
SD_DOWN = 1,
SD_BEGIN = 2,
SD_END = 3
} EScrollingDirection;
protected:
LLMenuGL(const LLMenuGL::Params& p);
friend class LLUICtrlFactory;
// let branching menu items use my protected traversal methods
friend class LLMenuItemBranchGL;
public:
virtual ~LLMenuGL( void );
void parseChildXML(LLXMLNodePtr child, LLView* parent);
// LLView Functionality
/*virtual*/ bool handleUnicodeCharHere( llwchar uni_char );
/*virtual*/ bool handleHover( S32 x, S32 y, MASK mask );
/*virtual*/ bool handleScrollWheel( S32 x, S32 y, S32 clicks );
/*virtual*/ void draw( void );
/*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha);
/*virtual*/ void setVisible(bool visible);
/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
/*virtual*/ void deleteAllChildren();
/*virtual*/ void removeChild( LLView* ctrl);
/*virtual*/ bool postBuild();
virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
virtual bool handleAcceleratorKey(KEY key, MASK mask);
LLMenuGL* findChildMenuByName(std::string_view name, bool recurse) const;
bool clearHoverItem();
// return the name label
const std::string& getLabel( void ) const { return mLabel.getString(); }
void setLabel(const LLStringExplicit& label) { mLabel = label; }
// background colors
void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; }
const LLUIColor& getBackgroundColor() const { return mBackgroundColor; }
void setBackgroundVisible( bool b ) { mBgVisible = b; }
void setCanTearOff(bool tear_off);
// add a separator to this menu
virtual bool addSeparator();
// for branching menu items, bring sub menus up to root level of menu hierarchy
virtual void updateParent( LLView* parentp );
// setItemEnabled() - pass the name and the enable flag for a
// menu item. true will make sure it's enabled, false will disable
// it.
void setItemEnabled(std::string_view name, bool enable );
// propagate message to submenus
void setEnabledSubMenus(bool enable);
void setItemVisible(std::string_view name, bool visible);
void setItemLabel(const std::string &name, const std::string &label);
// sets the left,bottom corner of menu, useful for popups
void setLeftAndBottom(S32 left, S32 bottom);
virtual bool handleJumpKey(KEY key);
virtual bool jumpKeysActive();
virtual bool isOpen();
void needsArrange() { mNeedsArrange = true; }
// Shape this menu to fit the current state of the children, and
// adjust the child rects to fit. This is called automatically
// when you add items. *FIX: We may need to deal with visibility
// arrangement.
virtual void arrange( void );
void arrangeAndClear( void );
// remove all items on the menu
void empty( void );
// erase group of items from menu
void erase( S32 begin, S32 end, bool arrange = true );
// add new item at position
void insert( S32 begin, LLView * ctrl, bool arrange = true );
void setItemLastSelected(LLMenuItemGL* item); // must be in menu
U32 getItemCount(); // number of menu items
LLMenuItemGL* getItem(S32 number); // 0 = first item
LLMenuItemGL* getItem(std::string name);
LLMenuItemGL* getHighlightedItem();
LLMenuItemGL* highlightNextItem(LLMenuItemGL* cur_item, bool skip_disabled = true);
LLMenuItemGL* highlightPrevItem(LLMenuItemGL* cur_item, bool skip_disabled = true);
void buildDrawLabels();
void createJumpKeys();
// Show popup at a specific location, in the spawn_view's coordinate frame
static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y, S32 mouse_x = 0, S32 mouse_y = 0);
// Whether to drop shadow menu bar
void setDropShadowed( const bool shadowed );
void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); }
LLMenuItemGL* getParentMenuItem() const { return dynamic_cast<LLMenuItemGL*>(mParentMenuItem.get()); }
void setTornOff(bool torn_off);
bool getTornOff() { return mTornOff; }
bool getCanTearOff() { return mTearOffItem != NULL; }
KEY getJumpKey() const { return mJumpKey; }
void setJumpKey(KEY key) { mJumpKey = key; }
static void setKeyboardMode(bool mode) { sKeyboardMode = mode; }
static bool getKeyboardMode() { return sKeyboardMode; }
S32 getShortcutPad() { return mShortcutPad; }
bool scrollItems(EScrollingDirection direction);
bool isScrollable() const { return mScrollable; }
static class LLMenuHolderGL* sMenuContainer;
void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; }
bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; }
void setAlwaysShowMenu(bool show) { mAlwaysShowMenu = show; }
bool getAlwaysShowMenu() { return mAlwaysShowMenu; }
// add a context menu branch
bool appendContextSubMenu(LLMenuGL *menu);
const LLFontGL *getFont() const { return mFont; }
// <FS:Ansariel> Items-accessor
typedef std::list< LLMenuItemGL* > item_list_t;
item_list_t* getItems() { return &mItems; }
protected:
void createSpilloverBranch();
void cleanupSpilloverBranch();
// Add the menu item to this menu.
virtual bool append( LLMenuItemGL* item );
// add a menu - this will create a cascading menu
virtual bool appendMenu( LLMenuGL* menu );
// Used in LLContextMenu and in LLTogleableMenu
// to add an item of context menu branch
bool addContextChild(LLView* view, S32 tab_group);
// TODO: create accessor methods for these?
//typedef std::list< LLMenuItemGL* > item_list_t; // <FS:Ansariel> Items-accessor
item_list_t mItems;
LLMenuItemGL*mFirstVisibleItem;
LLMenuItemGL *mArrowUpItem, *mArrowDownItem;
typedef std::map<KEY, LLMenuItemGL*> navigation_key_map_t;
navigation_key_map_t mJumpKeys;
S32 mLastMouseX;
S32 mLastMouseY;
S32 mMouseVelX;
S32 mMouseVelY;
U32 mMaxScrollableItems;
U32 mPreferredWidth;
bool mHorizontalLayout;
bool mScrollable;
bool mKeepFixedSize;
bool mNeedsArrange;
// Font for top menu items only
const LLFontGL* mFont;
private:
static LLColor4 sDefaultBackgroundColor;
static bool sKeyboardMode;
bool mAlwaysShowMenu;
LLUIColor mBackgroundColor;
bool mBgVisible;
LLHandle<LLView> mParentMenuItem;
LLUIString mLabel;
bool mDropShadowed; // Whether to drop shadow
bool mHasSelection;
LLFrameTimer mFadeTimer;
LLTimer mScrollItemsTimer;
bool mTornOff;
class LLMenuItemTearOffGL* mTearOffItem;
class LLMenuItemBranchGL* mSpilloverBranch;
LLMenuGL* mSpilloverMenu;
KEY mJumpKey;
bool mCreateJumpKeys;
S32 mShortcutPad;
bool mResetScrollPositionOnShow;
}; // end class LLMenuGL
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemBranchGL
//
// The LLMenuItemBranchGL represents a menu item that has a
// sub-menu. This is used to make cascading menus.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuItemBranchGL : public LLMenuItemGL
{
public:
struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
{
Optional<LLMenuGL*> branch;
};
protected:
LLMenuItemBranchGL(const Params&);
friend class LLUICtrlFactory;
public:
virtual ~LLMenuItemBranchGL();
virtual bool handleMouseUp(S32 x, S32 y, MASK mask);
virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
virtual bool handleAcceleratorKey(KEY key, MASK mask);
// check if we've used these accelerators already
virtual bool addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp);
// called to rebuild the draw label
virtual void buildDrawLabel( void );
virtual void onCommit( void );
virtual bool handleKey(KEY key, MASK mask, bool called_from_parent);
virtual bool handleUnicodeChar(llwchar uni_char, bool called_from_parent);
// set the hover status (called by it's menu) and if the object is
// active. This is used for behavior transfer.
virtual void setHighlight( bool highlight );
virtual bool handleKeyHere(KEY key, MASK mask);
virtual bool isActive() const;
virtual bool isOpen() const;
LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); }
virtual void updateBranchParent( LLView* parentp );
// LLView Functionality
virtual void onVisibilityChange( bool curVisibilityIn );
virtual void draw();
virtual void setEnabledSubMenus(bool enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); }
virtual void openMenu();
virtual LLView* getChildView(std::string_view name, bool recurse = true) const;
virtual LLView* findChildView(std::string_view name, bool recurse = true) const;
private:
LLHandle<LLView> mBranchHandle;
}; // end class LLMenuItemBranchGL
//-----------------------------------------------------------------------------
// class LLContextMenu
// A context menu
//-----------------------------------------------------------------------------
class LLContextMenu
: public LLMenuGL
{
public:
struct Params : public LLInitParam::Block<Params, LLMenuGL::Params>
{
Params()
{
changeDefault(visible, false);
}
};
protected:
LLContextMenu(const Params& p);
friend class LLUICtrlFactory;
public:
virtual ~LLContextMenu() {}
// LLView Functionality
// can't set visibility directly, must call show or hide
virtual void setVisible (bool visible);
virtual void show (S32 x, S32 y, LLView* spawning_view = NULL);
virtual void hide ();
virtual bool handleHover ( S32 x, S32 y, MASK mask );
virtual bool handleRightMouseDown( S32 x, S32 y, MASK mask );
virtual bool handleRightMouseUp ( S32 x, S32 y, MASK mask );
virtual bool addChild (LLView* view, S32 tab_group = 0);
LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); }
LLView* getSpawningView() const { return mSpawningViewHandle.get(); }
void setSpawningView(LLHandle<LLView> spawning_view) { mSpawningViewHandle = spawning_view; }
protected:
bool mHoveredAnyItem;
LLMenuItemGL* mHoverItem;
LLRootHandle<LLContextMenu> mHandle;
LLHandle<LLView> mSpawningViewHandle;
// <FS:ND>FIRE-9257; Hold a handle for mHoverItem so we can check if the item it already deleted.
LLHandle<LLView> mHoverItemHandle;
// </FS:ND>
};
//-----------------------------------------------------------------------------
// class LLContextMenuBranch
// A branch to another context menu
//-----------------------------------------------------------------------------
class LLContextMenuBranch : public LLMenuItemGL
{
public:
struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
{
Mandatory<LLContextMenu*> branch;
};
LLContextMenuBranch(const Params&);
virtual ~LLContextMenuBranch();
// called to rebuild the draw label
virtual void buildDrawLabel( void );
// onCommit() - do the primary funcationality of the menu item.
virtual void onCommit( void );
LLContextMenu* getBranch() { return mBranch.get(); }
void setHighlight( bool highlight );
protected:
void showSubMenu();
LLHandle<LLContextMenu> mBranch;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuBarGL
//
// A menu bar displays menus horizontally.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuBarGL : public LLMenuGL
{
public:
struct Params : public LLInitParam::Block<Params, LLMenuGL::Params>
{};
LLMenuBarGL( const Params& p );
virtual ~LLMenuBarGL();
/*virtual*/ bool handleAcceleratorKey(KEY key, MASK mask);
/*virtual*/ bool handleKeyHere(KEY key, MASK mask);
/*virtual*/ bool handleJumpKey(KEY key);
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask);
/*virtual*/ void draw();
/*virtual*/ bool jumpKeysActive();
// add a vertical separator to this menu
virtual bool addSeparator();
// LLView Functionality
virtual bool handleHover( S32 x, S32 y, MASK mask );
// Returns x position of rightmost child, usually Help menu
S32 getRightmostMenuEdge();
void resetMenuTrigger() { mAltKeyTrigger = false; }
private:
// add a menu - this will create a drop down menu.
virtual bool appendMenu( LLMenuGL* menu );
// rearrange the child rects so they fit the shape of the menu
// bar.
virtual void arrange( void );
void checkMenuTrigger();
std::list <LLMenuKeyboardBinding*> mAccelerators;
bool mAltKeyTrigger;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuHolderGL
//
// High level view that serves as parent for all menus
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuHolderGL : public LLPanel
{
public:
struct Params : public LLInitParam::Block<Params, LLPanel::Params>
{};
LLMenuHolderGL(const Params& p);
virtual ~LLMenuHolderGL() {}
virtual bool hideMenus();
void reshape(S32 width, S32 height, bool called_from_parent = true);
void setCanHide(bool can_hide) { mCanHide = can_hide; }
// LLView functionality
virtual void draw();
virtual bool handleMouseDown( S32 x, S32 y, MASK mask );
virtual bool handleRightMouseDown( S32 x, S32 y, MASK mask );
// Close context menus on right mouse up not handled by menus.
/*virtual*/ bool handleRightMouseUp( S32 x, S32 y, MASK mask );
virtual bool handleKey(KEY key, MASK mask, bool called_from_parent);
virtual const LLRect getMenuRect() const { return getLocalRect(); }
LLView*const getVisibleMenu() const;
virtual bool hasVisibleMenu() const {return getVisibleMenu() != NULL;}
static void setActivatedItem(LLMenuItemGL* item);
// Need to detect if mouse-up after context menu spawn has moved.
// If not, need to keep the menu up.
static LLCoordGL sContextMenuSpawnPos;
private:
static LLHandle<LLView> sItemLastSelectedHandle;
static LLFrameTimer sItemActivationTimer;
bool mCanHide;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLTearOffMenu
//
// Floater that hosts a menu
// https://wiki.lindenlab.com/mediawiki/index.php?title=LLTearOffMenu&oldid=81344
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTearOffMenu : public LLFloater
{
public:
static LLTearOffMenu* create(LLMenuGL* menup);
virtual ~LLTearOffMenu();
virtual void draw(void);
virtual void onFocusReceived();
virtual void onFocusLost();
virtual bool handleUnicodeChar(llwchar uni_char, bool called_from_parent);
virtual bool handleKeyHere(KEY key, MASK mask);
virtual void translate(S32 x, S32 y);
void updateSize();
private:
LLTearOffMenu(LLMenuGL* menup);
void closeTearOff();
LLView* mOldParent;
LLMenuGL* mMenu;
S32 mTargetHeight;
bool mQuitRequested;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemTearOffGL
//
// This class represents a separator.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMenuItemTearOffGL : public LLMenuItemGL
{
public:
struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
{};
LLMenuItemTearOffGL( const Params& );
virtual void onCommit(void);
virtual void draw(void);
virtual U32 getNominalHeight() const;
LLFloater* getParentFloater();
};
// *TODO: this is currently working, so finish implementation
class LLEditMenuHandlerMgr
{
public:
LLEditMenuHandlerMgr& getInstance() {
static LLEditMenuHandlerMgr instance;
return instance;
}
virtual ~LLEditMenuHandlerMgr() {}
private:
LLEditMenuHandlerMgr() {};
};
// *TODO: Eliminate
// For backwards compatability only; generally just use boost::bind
class view_listener_t : public boost::signals2::trackable
{
public:
virtual bool handleEvent(const LLSD& userdata) = 0;
view_listener_t() { sListeners.insert(this); }
virtual ~view_listener_t() { sListeners.erase(this); }
static void addEnable(view_listener_t* listener, const std::string& name)
{
LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2));
}
static void addCommit(view_listener_t* listener, const std::string& name)
{
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2));
}
static void addMenu(view_listener_t* listener, const std::string& name)
{
// For now, add to both click and enable registries
addEnable(listener, name);
addCommit(listener, name);
}
static void cleanup()
{
listener_vector_t listeners(sListeners.begin(), sListeners.end());
sListeners.clear();
std::for_each(listeners.begin(), listeners.end(), DeletePointer());
listeners.clear();
}
private:
typedef std::set<view_listener_t*> listener_map_t;
typedef std::vector<view_listener_t*> listener_vector_t;
static listener_map_t sListeners;
};
#endif // LL_LLMENUGL_H
+348
View File
@@ -0,0 +1,348 @@
/**
* @file llmodaldialog.cpp
* @brief LLModalDialog base class
*
* $LicenseInfo:firstyear=2002&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$
*/
#include "linden_common.h"
#include "llmodaldialog.h"
#include "llfocusmgr.h"
#include "v4color.h"
#include "v2math.h"
#include "llui.h"
#include "llwindow.h"
#include "llkeyboard.h"
#include "llmenugl.h"
// static
std::list<LLModalDialog*> LLModalDialog::sModalStack;
LLModalDialog::LLModalDialog( const LLSD& key, bool modal )
: LLFloater(key),
mModal( modal )
{
if (modal)
{
setCanMinimize(false);
setCanClose(false);
}
setVisible( false );
setBackgroundVisible(true);
setBackgroundOpaque(true);
centerOnScreen(); // default position
mCloseSignal.connect(boost::bind(&LLModalDialog::stopModal, this));
}
LLModalDialog::~LLModalDialog()
{
// don't unlock focus unless we have it
if (gFocusMgr.childHasKeyboardFocus(this))
{
gFocusMgr.unlockFocus();
}
std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this);
if (iter != sModalStack.end())
{
LL_ERRS() << "Attempt to delete dialog while still in sModalStack!" << LL_ENDL;
}
LLUI::getInstance()->removePopup(this);
}
// virtual
bool LLModalDialog::postBuild()
{
return LLFloater::postBuild();
}
// virtual
void LLModalDialog::openFloater(const LLSD& key)
{
// SJB: Hack! Make sure we don't ever host a modal dialog
LLMultiFloater* thost = LLFloater::getFloaterHost();
LLFloater::setFloaterHost(NULL);
LLFloater::openFloater(key);
LLFloater::setFloaterHost(thost);
}
void LLModalDialog::reshape(S32 width, S32 height, bool called_from_parent)
{
LLFloater::reshape(width, height, called_from_parent);
centerOnScreen();
}
// virtual
void LLModalDialog::onOpen(const LLSD& key)
{
if (mModal)
{
// If Modal, Hide the active modal dialog
if (!sModalStack.empty())
{
LLModalDialog* front = sModalStack.front();
if (front != this)
{
front->setVisible(false);
}
}
// This is a modal dialog. It sucks up all mouse and keyboard operations.
gFocusMgr.setMouseCapture( this );
LLUI::getInstance()->addPopup(this);
setFocus(true);
std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this);
if (iter != sModalStack.end())
{
// if already present, we want to move it to front.
sModalStack.erase(iter);
}
sModalStack.push_front(this);
}
}
void LLModalDialog::stopModal()
{
gFocusMgr.unlockFocus();
gFocusMgr.releaseFocusIfNeeded( this );
if (mModal)
{
std::list<LLModalDialog*>::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this);
if (iter != sModalStack.end())
{
sModalStack.erase(iter);
}
else
{
LL_WARNS() << "LLModalDialog::stopModal not in list!" << LL_ENDL;
}
}
if (!sModalStack.empty())
{
LLModalDialog* front = sModalStack.front();
front->setVisible(true);
}
}
void LLModalDialog::setVisible( bool visible )
{
if (mModal)
{
if( visible )
{
// This is a modal dialog. It sucks up all mouse and keyboard operations.
gFocusMgr.setMouseCapture( this );
// The dialog view is a root view
LLUI::getInstance()->addPopup(this);
setFocus( true );
}
else
{
gFocusMgr.releaseFocusIfNeeded( this );
}
}
LLFloater::setVisible( visible );
}
bool LLModalDialog::handleMouseDown(S32 x, S32 y, MASK mask)
{
LLView* popup_menu = LLMenuGL::sMenuContainer->getVisibleMenu();
if (popup_menu != NULL)
{
S32 mx, my;
LLUI::getInstance()->getMousePositionScreen(&mx, &my);
LLRect menu_screen_rc = popup_menu->calcScreenRect();
if(!menu_screen_rc.pointInRect(mx, my))
{
LLMenuGL::sMenuContainer->hideMenus();
}
}
if (mModal)
{
if (!LLFloater::handleMouseDown(x, y, mask))
{
// Click was outside the panel
make_ui_sound("UISndInvalidOp");
}
}
else
{
LLFloater::handleMouseDown(x, y, mask);
}
return true;
}
bool LLModalDialog::handleHover(S32 x, S32 y, MASK mask)
{
if( childrenHandleHover(x, y, mask) == NULL )
{
getWindow()->setCursor(UI_CURSOR_ARROW);
LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL;
}
LLView* popup_menu = LLMenuGL::sMenuContainer->getVisibleMenu();
if (popup_menu != NULL)
{
S32 mx, my;
LLUI::getInstance()->getMousePositionScreen(&mx, &my);
LLRect menu_screen_rc = popup_menu->calcScreenRect();
if(menu_screen_rc.pointInRect(mx, my))
{
S32 local_x = mx - popup_menu->getRect().mLeft;
S32 local_y = my - popup_menu->getRect().mBottom;
popup_menu->handleHover(local_x, local_y, mask);
gFocusMgr.setMouseCapture(NULL);
}
}
return true;
}
bool LLModalDialog::handleMouseUp(S32 x, S32 y, MASK mask)
{
childrenHandleMouseUp(x, y, mask);
return true;
}
bool LLModalDialog::handleScrollWheel(S32 x, S32 y, S32 clicks)
{
childrenHandleScrollWheel(x, y, clicks);
return true;
}
bool LLModalDialog::handleDoubleClick(S32 x, S32 y, MASK mask)
{
if (!LLFloater::handleDoubleClick(x, y, mask))
{
// Click outside the panel
make_ui_sound("UISndInvalidOp");
}
return true;
}
bool LLModalDialog::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
LLMenuGL::sMenuContainer->hideMenus();
childrenHandleRightMouseDown(x, y, mask);
return true;
}
bool LLModalDialog::handleKeyHere(KEY key, MASK mask )
{
LLFloater::handleKeyHere(key, mask );
if (mModal)
{
// Suck up all keystokes except CTRL-Q.
bool is_quit = ('Q' == key) && (MASK_CONTROL == mask);
return !is_quit;
}
else
{
// don't process escape key until message box has been on screen a minimal amount of time
// to avoid accidentally destroying the message box when user is hitting escape at the time it appears
bool enough_time_elapsed = mVisibleTime.getElapsedTimeF32() > 1.0f;
if (enough_time_elapsed && key == KEY_ESCAPE)
{
closeFloater();
return true;
}
return false;
}
}
// virtual
void LLModalDialog::draw()
{
static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow");
gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0,
shadow_color, DROP_SHADOW_FLOATER);
LLFloater::draw();
// Focus retrieval moved to LLFloaterView::refresh()
}
void LLModalDialog::centerOnScreen()
{
LLVector2 window_size = LLUI::getInstance()->getWindowSize();
centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY])));
}
// static
void LLModalDialog::onAppFocusLost()
{
if( !sModalStack.empty() )
{
LLModalDialog* instance = LLModalDialog::sModalStack.front();
if( gFocusMgr.childHasMouseCapture( instance ) )
{
gFocusMgr.setMouseCapture( NULL );
}
instance->setFocus(false);
}
}
// static
void LLModalDialog::onAppFocusGained()
{
if( !sModalStack.empty() )
{
LLModalDialog* instance = LLModalDialog::sModalStack.front();
// This is a modal dialog. It sucks up all mouse and keyboard operations.
gFocusMgr.setMouseCapture( instance );
instance->setFocus(true);
LLUI::getInstance()->addPopup(instance);
instance->centerOnScreen();
}
}
void LLModalDialog::shutdownModals()
{
// This method is only for use during app shutdown. ~LLModalDialog()
// checks sModalStack, and if the dialog instance is still there, it
// crumps with "Attempt to delete dialog while still in sModalStack!" But
// at app shutdown, all bets are off. If the user asks to shut down the
// app, we shouldn't have to care WHAT's open. Put differently, if a modal
// dialog is so crucial that we can't let the user terminate until s/he
// addresses it, we should reject a termination request. The current state
// of affairs is that we accept it, but then produce an LL_ERRS() popup that
// simply makes our software look unreliable.
sModalStack.clear();
}
+83
View File
@@ -0,0 +1,83 @@
/**
* @file llmodaldialog.h
* @brief LLModalDialog base class
*
* $LicenseInfo:firstyear=2002&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_LLMODALDIALOG_H
#define LL_LLMODALDIALOG_H
#include "llfloater.h"
#include "llframetimer.h"
class LLModalDialog;
// By default, a ModalDialog is modal, i.e. no other window can have focus
// However, for the sake of code reuse and simplicity, if mModal == false,
// the dialog behaves like a normal floater
// https://wiki.lindenlab.com/mediawiki/index.php?title=LLModalDialog&oldid=81385
class LLModalDialog : public LLFloater
{
public:
LLModalDialog( const LLSD& key, bool modal = true );
virtual ~LLModalDialog();
/*virtual*/ bool postBuild();
/*virtual*/ void openFloater(const LLSD& key = LLSD());
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true);
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleScrollWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ bool handleKeyHere(KEY key, MASK mask );
/*virtual*/ void setVisible(bool visible);
/*virtual*/ void draw();
bool isModal() const { return mModal; }
void stopModal();
static void onAppFocusLost();
static void onAppFocusGained();
static S32 activeCount() { return static_cast<S32>(sModalStack.size()); }
static void shutdownModals();
protected:
void centerOnScreen();
private:
LLFrameTimer mVisibleTime;
const bool mModal;
static std::list<LLModalDialog*> sModalStack; // Top of stack is currently being displayed
};
#endif // LL_LLMODALDIALOG_H
+611
View File
@@ -0,0 +1,611 @@
/**
* @file llmultifloater.cpp
* @brief LLFloater that hosts other floaters
*
* $LicenseInfo:firstyear=2002&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$
*/
// Floating "windows" within the GL display, like the inventory floater,
// mini-map floater, etc.
#include "linden_common.h"
#include "llmultifloater.h"
#include "llresizehandle.h"
#include "lldraghandle.h"
//
// LLMultiFloater
//
LLMultiFloater::LLMultiFloater(const LLSD& key, const LLFloater::Params& params)
: LLFloater(key),
mTabContainer(NULL),
mTabPos(LLTabContainer::TOP),
mAutoResize(true),
mOrigMinWidth(params.min_width),
mOrigMinHeight(params.min_height)
{
}
void LLMultiFloater::buildTabContainer()
{
const LLFloater::Params& default_params = LLFloater::getDefaultParams();
S32 floater_header_size = default_params.header_height;
LLTabContainer::Params p;
p.name(std::string("Preview Tabs"));
p.rect(LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - floater_header_size, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0));
p.tab_position(mTabPos);
p.follows.flags(FOLLOWS_ALL);
p.commit_callback.function(boost::bind(&LLMultiFloater::onTabSelected, this));
mTabContainer = LLUICtrlFactory::create<LLTabContainer>(p);
addChild(mTabContainer);
if (isResizable())
{
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
}
}
void LLMultiFloater::onClose(bool app_quitting)
{
if(isMinimized())
{
setMinimized(false);
}
LLFloater::onClose(app_quitting);
}
void LLMultiFloater::draw()
{
if (mTabContainer->getTabCount() == 0)
{
//RN: could this potentially crash in draw hierarchy?
closeFloater();
}
else
{
LLFloater::draw();
}
}
bool LLMultiFloater::closeAllFloaters()
{
S32 tabToClose = 0;
S32 lastTabCount = mTabContainer->getTabCount();
while (tabToClose < mTabContainer->getTabCount())
{
LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose);
first_floater->closeFloater();
if(lastTabCount == mTabContainer->getTabCount())
{
//Tab did not actually close, possibly due to a pending Save Confirmation dialog..
//so try and close the next one in the list...
tabToClose++;
}
else
{
//Tab closed ok.
lastTabCount = mTabContainer->getTabCount();
}
}
if( mTabContainer->getTabCount() != 0 )
return false; // Couldn't close all the tabs (pending save dialog?) so return false.
return true; //else all tabs were successfully closed...
}
void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
{
static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
const LLFloater::Params& default_params = LLFloater::getDefaultParams();
S32 floater_header_size = default_params.header_height;
S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2);
S32 new_height = llmax(getRect().getHeight(), content_height + floater_header_size + tabcntr_header_height);
if (isMinimized())
{
LLRect newrect;
newrect.setLeftTopAndSize(getExpandedRect().mLeft, getExpandedRect().mTop, new_width, new_height);
setExpandedRect(newrect);
}
else
{
S32 old_height = getRect().getHeight();
reshape(new_width, new_height);
// keep top left corner in same position
translate(0, old_height - new_height);
}
}
/**
void addFloater(LLFloater* floaterp, bool select_added_floater)
Adds the LLFloater pointed to by floaterp to this.
If floaterp is already hosted by this, then it is re-added to get
new titles, etc.
If select_added_floater is true, the LLFloater pointed to by floaterp will
become the selected tab in this
Affects: mTabContainer, floaterp
**/
void LLMultiFloater::addFloater(LLFloater* floaterp, bool select_added_floater, LLTabContainer::eInsertionPoint insertion_point)
{
if (!floaterp)
{
return;
}
if (!mTabContainer)
{
LL_ERRS() << "Tab Container used without having been initialized." << LL_ENDL;
return;
}
if (floaterp->getHost() == this)
{
// already hosted by me, remove
// do this so we get updated title, etc.
mFloaterDataMap.erase(floaterp->getHandle());
mTabContainer->removeTabPanel(floaterp);
}
else if (floaterp->getHost())
{
// floaterp is hosted by somebody else and
// this is adding it, so remove it from its old host
floaterp->getHost()->removeFloater(floaterp);
}
else if (floaterp->getParent() == gFloaterView)
{
// rehost preview floater as child panel
gFloaterView->removeChild(floaterp);
}
// store original configuration
LLFloaterData floater_data;
floater_data.mWidth = floaterp->getRect().getWidth();
floater_data.mHeight = floaterp->getRect().getHeight();
floater_data.mCanMinimize = floaterp->isMinimizeable();
floater_data.mCanResize = floaterp->isResizable();
floater_data.mSaveRect = floaterp->mSaveRect;
// remove minimize and close buttons
floaterp->setCanMinimize(false);
floaterp->setCanResize(false);
floaterp->setCanDrag(false);
floaterp->mSaveRect = false;
floaterp->storeRectControl();
// avoid double rendering of floater background (makes it more opaque)
floaterp->setBackgroundVisible(false);
// <FS> Update torn off status and add title bar; Do this AFTER we stored the original rect!
if (!mHostedFloaterShowtitlebar)
{
floaterp->getDragHandle()->setTitleVisible(false);
LLRect rect = floaterp->getRect();
rect.mTop -= floaterp->getHeaderHeight();
floaterp->setRect(rect);
}
// </FS>
if (mAutoResize)
{
growToFit(floater_data.mWidth, floater_data.mHeight);
}
//add the panel, add it to proper maps
mTabContainer->addTabPanel(
LLTabContainer::TabPanelParams()
.panel(floaterp)
.label(floaterp->getShortTitle())
.insert_at(insertion_point));
mFloaterDataMap[floaterp->getHandle()] = floater_data;
updateResizeLimits();
if ( select_added_floater )
{
mTabContainer->selectTabPanel(floaterp);
}
else
{
// reassert visible tab (hiding new floater if necessary)
mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
}
floaterp->setHost(this);
if (isMinimized())
{
floaterp->setVisible(false);
}
// Tabs sometimes overlap resize handle
moveResizeHandlesToFront();
}
void LLMultiFloater::updateFloaterTitle(LLFloater* floaterp)
{
S32 index = mTabContainer->getIndexForPanel(floaterp);
if (index != -1)
{
mTabContainer->setPanelTitle(index, floaterp->getShortTitle());
// <FS:TS> If the tab we're updating is the current tab, then
// update the overall title too, since we're showing it
// exclusively now.
if (!mHostedFloaterShowtitlebar && floaterp == mTabContainer->getCurrentPanel())
{
mDragHandle->setTitle(mTitle.getString() + " - " + floaterp->getTitle());
}
// </FS:TS>
}
}
/**
bool selectFloater(LLFloater* floaterp)
If the LLFloater pointed to by floaterp is hosted by this,
then its tab is selected and returns true. Otherwise returns false.
Affects: mTabContainer
**/
bool LLMultiFloater::selectFloater(LLFloater* floaterp)
{
return mTabContainer->selectTabPanel(floaterp);
}
// virtual
void LLMultiFloater::selectNextFloater()
{
mTabContainer->selectNextTab();
}
// virtual
void LLMultiFloater::selectPrevFloater()
{
mTabContainer->selectPrevTab();
}
void LLMultiFloater::showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point)
{
if(!floaterp) return;
// we won't select a panel that already is selected
// it is hard to do this internally to tab container
// as tab selection is handled via index and the tab at a given
// index might have changed
if (floaterp != mTabContainer->getCurrentPanel() &&
!mTabContainer->selectTabPanel(floaterp))
{
addFloater(floaterp, true, insertion_point);
}
}
void LLMultiFloater::removeFloater(LLFloater* floaterp)
{
if (!floaterp || floaterp->getHost() != this )
return;
// <FS> Update torn off status and add title bar
if (!mHostedFloaterShowtitlebar)
{
floaterp->getDragHandle()->setTitleVisible(true);
LLRect rect = floaterp->getRect();
rect.mTop += floaterp->getHeaderHeight();
floaterp->setRect(rect);
}
// </FS>
floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle());
if (found_data_it != mFloaterDataMap.end())
{
LLFloaterData& floater_data = found_data_it->second;
floaterp->setCanMinimize(floater_data.mCanMinimize);
floaterp->mSaveRect = floater_data.mSaveRect;
if (!floater_data.mCanResize)
{
// restore original size
floaterp->reshape(floater_data.mWidth, floater_data.mHeight);
}
floaterp->setCanResize(floater_data.mCanResize);
mFloaterDataMap.erase(found_data_it);
}
mTabContainer->removeTabPanel(floaterp);
floaterp->setBackgroundVisible(true);
floaterp->setCanDrag(true);
floaterp->setHost(NULL);
floaterp->applyRectControl();
// <FS:Zi> Make sure the floater doesn't resize with screen size changes
floaterp->setFollowsNone(); // <FS:Zi>
updateResizeLimits();
// <FS> Use dynamic cast instead of c-style cast; found by Sovereign Engineer
//tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
LLFloater* tab_floaterp = dynamic_cast<LLFloater*>(mTabContainer->getCurrentPanel());
if (tab_floaterp)
{
tabOpen(tab_floaterp, false);
}
// </FS>
}
void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click)
{
// default implementation does nothing
}
void LLMultiFloater::tabClose()
{
if (mTabContainer->getTabCount() == 0)
{
// no more children, close myself
closeFloater();
}
}
void LLMultiFloater::setVisible(bool visible)
{
// *FIX: shouldn't have to do this, fix adding to minimized multifloater
LLFloater::setVisible(visible);
if (mTabContainer)
{
LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
if (cur_floaterp)
{
cur_floaterp->setVisible(visible);
}
// if no tab selected, and we're being shown,
// select last tab to be added
if (visible && !cur_floaterp)
{
mTabContainer->selectLastTab();
}
}
}
bool LLMultiFloater::handleKeyHere(KEY key, MASK mask)
{
// <FS:Ansariel> This won't work - CTRL-W is intercepted by LLFileCloseWindow!
if (key == 'W' && mask == MASK_CONTROL)
{
LLFloater* floater = getActiveFloater();
// is user closeable and is system closeable
if (floater && floater->canClose() && floater->isCloseable())
{
floater->closeFloater();
// EXT-5695 (Tabbed IM window loses focus if close any tabs by Ctrl+W)
// bring back focus on tab container if there are any tab left
if(mTabContainer->getTabCount() > 0)
{
mTabContainer->setFocus(true);
}
}
return true;
}
return LLFloater::handleKeyHere(key, mask);
}
bool LLMultiFloater::addChild(LLView* child, S32 tab_group)
{
LLTabContainer* tab_container = dynamic_cast<LLTabContainer*>(child);
if (tab_container)
{
// store pointer to tab container
setTabContainer(tab_container);
}
// then go ahead and add child as usual
return LLFloater::addChild(child, tab_group);
}
LLFloater* LLMultiFloater::getActiveFloater()
{
return (LLFloater*)mTabContainer->getCurrentPanel();
}
S32 LLMultiFloater::getFloaterCount()
{
return mTabContainer->getTabCount();
}
/**
bool isFloaterFlashing(LLFloater* floaterp)
Returns true if the LLFloater pointed to by floaterp
is currently in a flashing state and is hosted by this.
False otherwise.
Requires: floaterp != NULL
**/
bool LLMultiFloater::isFloaterFlashing(LLFloater* floaterp)
{
if ( floaterp && floaterp->getHost() == this )
return mTabContainer->getTabPanelFlashing(floaterp);
return false;
}
/**
bool setFloaterFlashing(LLFloater* floaterp, bool flashing)
Sets the current flashing state of the LLFloater pointed
to by floaterp to be the bool flashing if the LLFloater pointed
to by floaterp is hosted by this.
Requires: floaterp != NULL
**/
void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, bool flashing)
{
if ( floaterp && floaterp->getHost() == this )
mTabContainer->setTabPanelFlashing(floaterp, flashing);
}
void LLMultiFloater::onTabSelected()
{
LLFloater* floaterp = dynamic_cast<LLFloater*>(mTabContainer->getCurrentPanel());
if (floaterp)
{
tabOpen(floaterp, true);
// <FS> Update torn off status and add title bar
if (!mHostedFloaterShowtitlebar)
{
mDragHandle->setTitle(mTitle.getString() + " - " + floaterp->getTitle());
}
// </FS>
}
}
// <FS> Update torn off status and add title bar
void LLMultiFloater::setTabContainer(LLTabContainer* tab_container)
{
if (!mTabContainer)
{
mTabContainer = tab_container;
mTabContainer->setCommitCallback(boost::bind(&LLMultiFloater::onTabSelected, this));
}
}
// </FS>
void LLMultiFloater::setCanResize(bool can_resize)
{
LLFloater::setCanResize(can_resize);
if (!mTabContainer) return;
if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
{
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
}
else
{
mTabContainer->setRightTabBtnOffset(0);
}
}
bool LLMultiFloater::postBuild()
{
mCloseSignal.connect(boost::bind(&LLMultiFloater::closeAllFloaters, this));
// remember any original xml minimum size
getResizeLimits(&mOrigMinWidth, &mOrigMinHeight);
if (mTabContainer)
{
return true;
}
// <FS> Update torn off status and add title bar
//mTabContainer = getChild<LLTabContainer>("Preview Tabs");
setTabContainer(getChild<LLTabContainer>("Preview Tabs"));
// </FS>
setCanResize(mResizable);
return true;
}
void LLMultiFloater::updateResizeLimits()
{
// initialize minimum size constraint to the original xml values.
S32 new_min_width = mOrigMinWidth;
S32 new_min_height = mOrigMinHeight;
computeResizeLimits(new_min_width, new_min_height);
setResizeLimits(new_min_width, new_min_height);
S32 cur_height = getRect().getHeight();
S32 new_width = llmax(getRect().getWidth(), new_min_width);
S32 new_height = llmax(getRect().getHeight(), new_min_height);
if (isMinimized())
{
const LLRect& expanded = getExpandedRect();
LLRect newrect;
newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height));
setExpandedRect(newrect);
}
else
{
reshape(new_width, new_height);
// make sure upper left corner doesn't move
translate(0, cur_height - getRect().getHeight());
// make sure this window is visible on screen when it has been modified
// (tab added, etc)
gFloaterView->adjustToFitScreen(this, true);
}
}
void LLMultiFloater::computeResizeLimits(S32& new_min_width, S32& new_min_height)
{
static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
const LLFloater::Params& default_params = LLFloater::getDefaultParams();
S32 floater_header_size = default_params.header_height;
S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
// possibly increase minimum size constraint due to children's minimums.
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
{
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
if (floaterp)
{
new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
new_min_height = llmax(new_min_height, floaterp->getMinHeight() + floater_header_size + tabcntr_header_height);
}
}
}
// <FS:Ansariel> CTRL-W doesn't work with multifloaters
void LLMultiFloater::closeDockedFloater()
{
LLFloater* floater = getActiveFloater();
// is user closeable and is system closeable
if (floater && floater->canClose() && floater->isCloseable())
{
floater->closeFloater();
// EXT-5695 (Tabbed IM window loses focus if close any tabs by Ctrl+W)
// bring back focus on tab container if there are any tab left
if(mTabContainer->getTabCount() > 0)
{
mTabContainer->setFocus(true);
}
else
{
// Call closeFloater() here so that focus gets properly handed over
closeFloater();
}
return;
}
// Close multifloater itself if we can't close any hosted floaters
closeFloater();
}
// <FS:Ansariel>
+108
View File
@@ -0,0 +1,108 @@
/**
* @file llmultifloater.h
* @brief LLFloater that hosts other floaters
*
* $LicenseInfo:firstyear=2002&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$
*/
// Floating "windows" within the GL display, like the inventory floater,
// mini-map floater, etc.
#ifndef LL_MULTI_FLOATER_H
#define LL_MULTI_FLOATER_H
#include "llfloater.h"
#include "lltabcontainer.h" // for LLTabContainer::eInsertionPoint
// https://wiki.lindenlab.com/mediawiki/index.php?title=LLMultiFloater&oldid=81376
class LLMultiFloater : public LLFloater
{
public:
LLMultiFloater(const LLSD& key, const Params& params = getDefaultParams());
virtual ~LLMultiFloater() {};
void buildTabContainer();
virtual bool postBuild();
/*virtual*/ void onClose(bool app_quitting);
virtual void draw();
virtual void setVisible(bool visible);
/*virtual*/ bool handleKeyHere(KEY key, MASK mask);
/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
virtual void setCanResize(bool can_resize);
virtual void growToFit(S32 content_width, S32 content_height);
virtual void addFloater(LLFloater* floaterp, bool select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
virtual void showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
virtual void removeFloater(LLFloater* floaterp);
virtual void tabOpen(LLFloater* opened_floater, bool from_click);
virtual void tabClose();
virtual bool selectFloater(LLFloater* floaterp);
virtual void selectNextFloater();
virtual void selectPrevFloater();
virtual LLFloater* getActiveFloater();
virtual bool isFloaterFlashing(LLFloater* floaterp);
virtual S32 getFloaterCount();
virtual void setFloaterFlashing(LLFloater* floaterp, bool flashing);
virtual bool closeAllFloaters(); //Returns false if the floater could not be closed due to pending confirmation dialogs
// <FS> Update torn off status and add title bar
//void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; } // LL Code
void setTabContainer(LLTabContainer* tab_container);
// </FS> Update torn off status and add title bar
void onTabSelected();
virtual void updateResizeLimits();
virtual void updateFloaterTitle(LLFloater* floaterp);
// <FS:Ansariel> CTRL-W doesn't work with multifloaters
void closeDockedFloater();
protected:
struct LLFloaterData
{
S32 mWidth;
S32 mHeight;
bool mCanMinimize;
bool mCanResize;
bool mSaveRect;
};
LLTabContainer* mTabContainer;
typedef std::map<LLHandle<LLFloater>, LLFloaterData> floater_data_map_t;
floater_data_map_t mFloaterDataMap;
LLTabContainer::TabPosition mTabPos;
bool mAutoResize;
S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late
private:
virtual void computeResizeLimits(S32& new_min_width, S32& new_min_height);
};
#endif // LL_MULTI_FLOATER_H
+880
View File
@@ -0,0 +1,880 @@
/**
* @file llmultisldr.cpp
* @brief LLMultiSlider base class
*
* $LicenseInfo:firstyear=2007&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$
*/
#include "linden_common.h"
#include "llmultislider.h"
#include "llui.h"
#include "llgl.h"
#include "llwindow.h"
#include "llfocusmgr.h"
#include "llkeyboard.h" // for the MASK constants
#include "llcontrol.h"
#include "lluictrlfactory.h"
#include "lluiimage.h"
#include <sstream>
static LLDefaultChildRegistry::Register<LLMultiSlider> r("multi_slider_bar");
const F32 FLOAT_THRESHOLD = 0.00001f;
S32 LLMultiSlider::mNameCounter = 0;
LLMultiSlider::SliderParams::SliderParams()
: name("name"),
value("value", 0.f)
{
}
LLMultiSlider::Params::Params()
: max_sliders("max_sliders", 1),
allow_overlap("allow_overlap", false),
loop_overlap("loop_overlap", false),
orientation("orientation"),
overlap_threshold("overlap_threshold", 0),
draw_track("draw_track", true),
use_triangle("use_triangle", false),
track_color("track_color"),
thumb_disabled_color("thumb_disabled_color"),
thumb_highlight_color("thumb_highlight_color"),
thumb_outline_color("thumb_outline_color"),
thumb_center_color("thumb_center_color"),
thumb_center_selected_color("thumb_center_selected_color"),
thumb_image("thumb_image"),
triangle_color("triangle_color"),
mouse_down_callback("mouse_down_callback"),
mouse_up_callback("mouse_up_callback"),
thumb_width("thumb_width"),
sliders("slider")
{}
LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
: LLF32UICtrl(p),
mMouseOffset( 0 ),
mMaxNumSliders(p.max_sliders),
mAllowOverlap(p.allow_overlap),
mLoopOverlap(p.loop_overlap),
mDrawTrack(p.draw_track),
mUseTriangle(p.use_triangle),
mTrackColor(p.track_color()),
mThumbOutlineColor(p.thumb_outline_color()),
mThumbCenterColor(p.thumb_center_color()),
mThumbCenterSelectedColor(p.thumb_center_selected_color()),
mDisabledThumbColor(p.thumb_disabled_color()),
mTriangleColor(p.triangle_color()),
mThumbWidth(p.thumb_width),
mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL),
mMouseDownSignal(NULL),
mMouseUpSignal(NULL)
{
mValue = LLSD::emptyMap();
mCurSlider = LLStringUtil::null;
if (mOrientation == HORIZONTAL)
{
mDragStartThumbRect = LLRect(0, getRect().getHeight(), p.thumb_width, 0);
}
else
{
mDragStartThumbRect = LLRect(0, p.thumb_width, getRect().getWidth(), 0);
}
if (p.mouse_down_callback.isProvided())
{
setMouseDownCallback(initCommitCallback(p.mouse_down_callback));
}
if (p.mouse_up_callback.isProvided())
{
setMouseUpCallback(initCommitCallback(p.mouse_up_callback));
}
if (p.overlap_threshold.isProvided() && p.overlap_threshold > mIncrement)
{
mOverlapThreshold = p.overlap_threshold - mIncrement;
}
else
{
mOverlapThreshold = 0;
}
for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin();
it != p.sliders.end();
++it)
{
if (it->name.isProvided())
{
addSlider(it->value, it->name);
}
else
{
addSlider(it->value);
}
}
mRoundedSquareImgp = LLUI::getUIImage("Rounded_Square");
if (p.thumb_image.isProvided())
{
mThumbImagep = LLUI::getUIImage(p.thumb_image());
}
mThumbHighlightColor = p.thumb_highlight_color.isProvided() ? p.thumb_highlight_color() : static_cast<LLUIColor>(gFocusMgr.getFocusColor());
}
LLMultiSlider::~LLMultiSlider()
{
delete mMouseDownSignal;
delete mMouseUpSignal;
}
F32 LLMultiSlider::getNearestIncrement(F32 value) const
{
value = llclamp(value, mMinValue, mMaxValue);
// Round to nearest increment (bias towards rounding down)
value -= mMinValue;
value += mIncrement / 2.0001f;
value -= fmod(value, mIncrement);
return mMinValue + value;
}
void LLMultiSlider::setSliderValue(const std::string& name, F32 value, bool from_event)
{
// exit if not there
if(!mValue.has(name)) {
return;
}
F32 newValue = getNearestIncrement(value);
// now, make sure no overlap
// if we want that
if(!mAllowOverlap) {
bool hit = false;
// look at the current spot
// and see if anything is there
LLSD::map_iterator mIt = mValue.beginMap();
// increment is our distance between points, use to eliminate round error
F32 threshold = mOverlapThreshold + (mIncrement / 4);
// If loop overlap is enabled, check if we overlap with points 'after' max value (project to lower)
F32 loop_up_check = (mLoopOverlap && (value + threshold) > mMaxValue) ? (value + threshold - mMaxValue + mMinValue) : mMinValue - 1.0f;
// If loop overlap is enabled, check if we overlap with points 'before' min value (project to upper)
F32 loop_down_check = (mLoopOverlap && (value - threshold) < mMinValue) ? (value - threshold - mMinValue + mMaxValue) : mMaxValue + 1.0f;
for(;mIt != mValue.endMap(); mIt++)
{
F32 locationVal = (F32)mIt->second.asReal();
// Check nearby values
F32 testVal = locationVal - newValue;
if (testVal > -threshold
&& testVal < threshold
&& mIt->first != name)
{
hit = true;
break;
}
if (mLoopOverlap)
{
// Check edge overlap values
if (locationVal < loop_up_check)
{
hit = true;
break;
}
if (locationVal > loop_down_check)
{
hit = true;
break;
}
}
}
// if none found, stop
if(hit) {
return;
}
}
// now set it in the map
mValue[name] = newValue;
// set the control if it's the current slider and not from an event
if (!from_event && name == mCurSlider)
{
setControlValue(mValue);
}
F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue);
if (mOrientation == HORIZONTAL)
{
S32 left_edge = mThumbWidth/2;
S32 right_edge = getRect().getWidth() - (mThumbWidth/2);
S32 x = left_edge + S32( t * (right_edge - left_edge) );
mThumbRects[name].mLeft = x - (mThumbWidth / 2);
mThumbRects[name].mRight = x + (mThumbWidth / 2);
}
else
{
S32 bottom_edge = mThumbWidth/2;
S32 top_edge = getRect().getHeight() - (mThumbWidth/2);
S32 x = bottom_edge + S32( t * (top_edge - bottom_edge) );
mThumbRects[name].mTop = x + (mThumbWidth / 2);
mThumbRects[name].mBottom = x - (mThumbWidth / 2);
}
}
void LLMultiSlider::setValue(const LLSD& value)
{
// only do if it's a map
if(value.isMap()) {
// add each value... the first in the map becomes the current
LLSD::map_const_iterator mIt = value.beginMap();
mCurSlider = mIt->first;
for(; mIt != value.endMap(); mIt++) {
setSliderValue(mIt->first, (F32)mIt->second.asReal(), true);
}
}
}
F32 LLMultiSlider::getSliderValue(const std::string& name) const
{
if (mValue.has(name))
{
return (F32)mValue[name].asReal();
}
return 0;
}
void LLMultiSlider::setCurSlider(const std::string& name)
{
if(mValue.has(name)) {
mCurSlider = name;
}
}
F32 LLMultiSlider::getSliderValueFromPos(S32 xpos, S32 ypos) const
{
F32 t = 0;
if (mOrientation == HORIZONTAL)
{
S32 left_edge = mThumbWidth / 2;
S32 right_edge = getRect().getWidth() - (mThumbWidth / 2);
xpos += mMouseOffset;
xpos = llclamp(xpos, left_edge, right_edge);
t = F32(xpos - left_edge) / (right_edge - left_edge);
}
else
{
S32 bottom_edge = mThumbWidth / 2;
S32 top_edge = getRect().getHeight() - (mThumbWidth / 2);
ypos += mMouseOffset;
ypos = llclamp(ypos, bottom_edge, top_edge);
t = F32(ypos - bottom_edge) / (top_edge - bottom_edge);
}
return((t * (mMaxValue - mMinValue)) + mMinValue);
}
LLRect LLMultiSlider::getSliderThumbRect(const std::string& name) const
{
auto it = mThumbRects.find(name);
if (it != mThumbRects.end())
return (*it).second;
return LLRect();
}
void LLMultiSlider::setSliderThumbImage(const std::string &name)
{
if (!name.empty())
{
mThumbImagep = LLUI::getUIImage(name);
}
else
clearSliderThumbImage();
}
void LLMultiSlider::clearSliderThumbImage()
{
mThumbImagep = NULL;
}
void LLMultiSlider::resetCurSlider()
{
mCurSlider = LLStringUtil::null;
}
const std::string& LLMultiSlider::addSlider()
{
return addSlider(mInitialValue);
}
const std::string& LLMultiSlider::addSlider(F32 val)
{
std::stringstream newName;
F32 initVal = val;
if(mValue.size() >= mMaxNumSliders) {
return LLStringUtil::null;
}
// create a new name
newName << "sldr" << mNameCounter;
mNameCounter++;
bool foundOne = findUnusedValue(initVal);
if(!foundOne) {
return LLStringUtil::null;
}
// add a new thumb rect
if (mOrientation == HORIZONTAL)
{
mThumbRects[newName.str()] = LLRect(0, getRect().getHeight(), mThumbWidth, 0);
}
else
{
mThumbRects[newName.str()] = LLRect(0, mThumbWidth, getRect().getWidth(), 0);
}
// add the value and set the current slider to this one
mValue.insert(newName.str(), initVal);
mCurSlider = newName.str();
// move the slider
setSliderValue(mCurSlider, initVal, true);
return mCurSlider;
}
bool LLMultiSlider::addSlider(F32 val, const std::string& name)
{
F32 initVal = val;
if(mValue.size() >= mMaxNumSliders) {
return false;
}
bool foundOne = findUnusedValue(initVal);
if(!foundOne) {
return false;
}
// add a new thumb rect
if (mOrientation == HORIZONTAL)
{
mThumbRects[name] = LLRect(0, getRect().getHeight(), mThumbWidth, 0);
}
else
{
mThumbRects[name] = LLRect(0, mThumbWidth, getRect().getWidth(), 0);
}
// add the value and set the current slider to this one
mValue.insert(name, initVal);
mCurSlider = name;
// move the slider
setSliderValue(mCurSlider, initVal, true);
return true;
}
bool LLMultiSlider::findUnusedValue(F32& initVal)
{
bool firstTry = true;
// find the first open slot starting with
// the initial value
while(true) {
bool hit = false;
// look at the current spot
// and see if anything is there
F32 threshold = mAllowOverlap ? FLOAT_THRESHOLD : mOverlapThreshold + (mIncrement / 4);
LLSD::map_iterator mIt = mValue.beginMap();
for(;mIt != mValue.endMap(); mIt++) {
F32 testVal = (F32)mIt->second.asReal() - initVal;
if(testVal > -threshold && testVal < threshold)
{
hit = true;
break;
}
}
// if we found one
if(!hit) {
break;
}
// increment and wrap if need be
initVal += mIncrement;
if(initVal > mMaxValue) {
initVal = mMinValue;
}
// stop if it's filled
if(initVal == mInitialValue && !firstTry) {
LL_WARNS() << "Whoa! Too many multi slider elements to add one to" << LL_ENDL;
return false;
}
firstTry = false;
continue;
}
return true;
}
void LLMultiSlider::deleteSlider(const std::string& name)
{
// can't delete last slider
if(mValue.size() <= 0) {
return;
}
// get rid of value from mValue and its thumb rect
mValue.erase(name);
mThumbRects.erase(name);
// set to the last created
if(mValue.size() > 0) {
std::map<std::string, LLRect>::iterator mIt = mThumbRects.end();
mIt--;
mCurSlider = mIt->first;
}
}
void LLMultiSlider::clear()
{
while(mThumbRects.size() > 0 && mValue.size() > 0) {
deleteCurSlider();
}
if (mThumbRects.size() > 0 || mValue.size() > 0)
{
LL_WARNS() << "Failed to fully clear Multi slider" << LL_ENDL;
}
LLF32UICtrl::clear();
}
bool LLMultiSlider::handleHover(S32 x, S32 y, MASK mask)
{
if( gFocusMgr.getMouseCapture() == this )
{
setCurSliderValue(getSliderValueFromPos(x, y));
onCommit();
getWindow()->setCursor(UI_CURSOR_ARROW);
LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL;
}
else
{
if (getEnabled())
{
mHoverSlider.clear();
std::map<std::string, LLRect>::iterator mIt = mThumbRects.begin();
for (; mIt != mThumbRects.end(); mIt++)
{
if (mIt->second.pointInRect(x, y))
{
mHoverSlider = mIt->first;
break;
}
}
}
else
{
mHoverSlider.clear();
}
getWindow()->setCursor(UI_CURSOR_ARROW);
LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL;
}
return true;
}
bool LLMultiSlider::handleMouseUp(S32 x, S32 y, MASK mask)
{
bool handled = false;
if( gFocusMgr.getMouseCapture() == this )
{
gFocusMgr.setMouseCapture( NULL );
if (mMouseUpSignal)
(*mMouseUpSignal)( this, LLSD() );
handled = true;
make_ui_sound("UISndClickRelease");
}
else
{
handled = true;
}
return handled;
}
bool LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask)
{
// only do sticky-focus on non-chrome widgets
if (!getIsChrome())
{
setFocus(true);
}
if (mMouseDownSignal)
(*mMouseDownSignal)( this, LLSD() );
if (MASK_CONTROL & mask) // if CTRL is modifying
{
setCurSliderValue(mInitialValue);
onCommit();
}
else
{
// scroll through thumbs to see if we have a new one selected and select that one
std::map<std::string, LLRect>::iterator mIt = mThumbRects.begin();
for(; mIt != mThumbRects.end(); mIt++) {
// check if inside. If so, set current slider and continue
if(mIt->second.pointInRect(x,y)) {
mCurSlider = mIt->first;
break;
}
}
if (!mCurSlider.empty())
{
// Find the offset of the actual mouse location from the center of the thumb.
if (mThumbRects[mCurSlider].pointInRect(x,y))
{
if (mOrientation == HORIZONTAL)
{
mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth / 2) - x;
}
else
{
mMouseOffset = (mThumbRects[mCurSlider].mBottom + mThumbWidth / 2) - y;
}
}
else
{
mMouseOffset = 0;
}
// Start dragging the thumb
// No handler needed for focus lost since this class has no state that depends on it.
gFocusMgr.setMouseCapture( this );
mDragStartThumbRect = mThumbRects[mCurSlider];
}
}
make_ui_sound("UISndClick");
return true;
}
bool LLMultiSlider::handleKeyHere(KEY key, MASK mask)
{
bool handled = false;
switch(key)
{
case KEY_UP:
case KEY_DOWN:
// eat up and down keys to be consistent
handled = true;
break;
case KEY_LEFT:
setCurSliderValue(getCurSliderValue() - getIncrement());
onCommit();
handled = true;
break;
case KEY_RIGHT:
setCurSliderValue(getCurSliderValue() + getIncrement());
onCommit();
handled = true;
break;
default:
break;
}
return handled;
}
/*virtual*/
void LLMultiSlider::onMouseLeave(S32 x, S32 y, MASK mask)
{
mHoverSlider.clear();
LLF32UICtrl::onMouseLeave(x, y, mask);
}
void LLMultiSlider::draw()
{
static LLUICachedControl<S32> extra_triangle_height ("UIExtraTriangleHeight", 0);
static LLUICachedControl<S32> extra_triangle_width ("UIExtraTriangleWidth", 0);
LLColor4 curThumbColor;
std::map<std::string, LLRect>::iterator mIt;
std::map<std::string, LLRect>::iterator curSldrIt;
std::map<std::string, LLRect>::iterator hoverSldrIt;
// Draw background and thumb.
// drawing solids requires texturing be disabled
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
LLRect rect(mDragStartThumbRect);
F32 opacity = getEnabled() ? 1.f : 0.3f;
// Track
static LLUICachedControl<S32> multi_track_height_width ("UIMultiTrackHeight", 0);
S32 height_offset = 0;
S32 width_offset = 0;
if (mOrientation == HORIZONTAL)
{
height_offset = (getRect().getHeight() - multi_track_height_width) / 2;
}
else
{
width_offset = (getRect().getWidth() - multi_track_height_width) / 2;
}
LLRect track_rect(width_offset, getRect().getHeight() - height_offset, getRect().getWidth() - width_offset, height_offset);
if(mDrawTrack)
{
track_rect.stretch(-1);
mRoundedSquareImgp->draw(track_rect, mTrackColor.get() % opacity);
}
// if we're supposed to use a drawn triangle
// simple gl call for the triangle
if(mUseTriangle) {
for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
gl_triangle_2d(
mIt->second.mLeft - extra_triangle_width,
mIt->second.mTop + extra_triangle_height,
mIt->second.mRight + extra_triangle_width,
mIt->second.mTop + extra_triangle_height,
mIt->second.mLeft + mIt->second.getWidth() / 2,
mIt->second.mBottom - extra_triangle_height,
mTriangleColor.get() % opacity, true);
}
}
else if (!mRoundedSquareImgp && !mThumbImagep)
{
// draw all the thumbs
curSldrIt = mThumbRects.end();
hoverSldrIt = mThumbRects.end();
for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
// choose the color
curThumbColor = mThumbCenterColor.get();
if(mIt->first == mCurSlider) {
curSldrIt = mIt;
continue;
}
if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this)
{
// draw last, after current one
hoverSldrIt = mIt;
continue;
}
// the draw command
gl_rect_2d(mIt->second, curThumbColor, true);
}
// now draw the current and hover sliders
if(curSldrIt != mThumbRects.end())
{
gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor.get(), true);
}
// and draw the drag start
if (gFocusMgr.getMouseCapture() == this)
{
gl_rect_2d(mDragStartThumbRect, mThumbCenterColor.get() % opacity, false);
}
else if (hoverSldrIt != mThumbRects.end())
{
gl_rect_2d(hoverSldrIt->second, mThumbCenterSelectedColor.get(), true);
}
}
else
{
LLMouseHandler* capture = gFocusMgr.getMouseCapture();
if (capture == this)
{
// draw drag start (ghost)
if (mThumbImagep)
{
mThumbImagep->draw(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f);
}
else
{
mRoundedSquareImgp->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f);
}
}
// draw the highlight
if (hasFocus())
{
if (!mCurSlider.empty())
{
if (mThumbImagep)
{
mThumbImagep->drawBorder(mThumbRects[mCurSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth());
}
else
{
mRoundedSquareImgp->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth());
}
}
}
if (!mHoverSlider.empty())
{
if (mThumbImagep)
{
mThumbImagep->drawBorder(mThumbRects[mHoverSlider], mThumbHighlightColor, gFocusMgr.getFocusFlashWidth());
}
else
{
mRoundedSquareImgp->drawBorder(mThumbRects[mHoverSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth());
}
}
// draw the thumbs
curSldrIt = mThumbRects.end();
hoverSldrIt = mThumbRects.end();
for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++)
{
// choose the color
curThumbColor = mThumbCenterColor.get();
if(mIt->first == mCurSlider)
{
// don't draw now, draw last
curSldrIt = mIt;
continue;
}
if (mIt->first == mHoverSlider && getEnabled() && gFocusMgr.getMouseCapture() != this)
{
// don't draw now, draw last, after current one
hoverSldrIt = mIt;
continue;
}
// the draw command
if (mThumbImagep)
{
if (getEnabled())
{
mThumbImagep->draw(mIt->second);
}
else
{
mThumbImagep->draw(mIt->second, LLColor4::grey % 0.8f);
}
}
else if (capture == this)
{
mRoundedSquareImgp->drawSolid(mIt->second, curThumbColor);
}
else
{
mRoundedSquareImgp->drawSolid(mIt->second, curThumbColor % opacity);
}
}
// draw cur and hover slider last
if(curSldrIt != mThumbRects.end())
{
if (mThumbImagep)
{
if (getEnabled())
{
mThumbImagep->draw(curSldrIt->second);
}
else
{
mThumbImagep->draw(curSldrIt->second, LLColor4::grey % 0.8f);
}
}
else if (capture == this)
{
mRoundedSquareImgp->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get());
}
else
{
mRoundedSquareImgp->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity);
}
}
if(hoverSldrIt != mThumbRects.end())
{
if (mThumbImagep)
{
mThumbImagep->draw(hoverSldrIt->second);
}
else
{
mRoundedSquareImgp->drawSolid(hoverSldrIt->second, mThumbCenterSelectedColor.get());
}
}
}
LLF32UICtrl::draw();
}
boost::signals2::connection LLMultiSlider::setMouseDownCallback( const commit_signal_t::slot_type& cb )
{
if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t();
return mMouseDownSignal->connect(cb);
}
boost::signals2::connection LLMultiSlider::setMouseUpCallback( const commit_signal_t::slot_type& cb )
{
if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t();
return mMouseUpSignal->connect(cb);
}
+161
View File
@@ -0,0 +1,161 @@
/**
* @file llmultislider.h
* @brief A simple multislider
*
* $LicenseInfo:firstyear=2007&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_MULTI_SLIDER_H
#define LL_MULTI_SLIDER_H
#include "llf32uictrl.h"
#include "v4color.h"
class LLUICtrlFactory;
class LLMultiSlider : public LLF32UICtrl
{
public:
struct SliderParams : public LLInitParam::Block<SliderParams>
{
Optional<std::string> name;
Mandatory<F32> value;
SliderParams();
};
struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params>
{
Optional<S32> max_sliders;
Optional<bool> allow_overlap,
loop_overlap,
draw_track,
use_triangle;
Optional<F32> overlap_threshold;
Optional<LLUIColor> track_color,
thumb_disabled_color,
thumb_highlight_color,
thumb_outline_color,
thumb_center_color,
thumb_center_selected_color,
triangle_color;
Optional<std::string> orientation,
thumb_image;
Optional<CommitCallbackParam> mouse_down_callback,
mouse_up_callback;
Optional<S32> thumb_width;
Multiple<SliderParams> sliders;
Params();
};
protected:
LLMultiSlider(const Params&);
friend class LLUICtrlFactory;
public:
virtual ~LLMultiSlider();
// Multi-slider rounds values to nearest increments (bias towards rounding down)
F32 getNearestIncrement(F32 value) const;
void setSliderValue(const std::string& name, F32 value, bool from_event = false);
F32 getSliderValue(const std::string& name) const;
F32 getSliderValueFromPos(S32 xpos, S32 ypos) const;
LLRect getSliderThumbRect(const std::string& name) const;
void setSliderThumbImage(const std::string &name);
void clearSliderThumbImage();
const std::string& getCurSlider() const { return mCurSlider; }
F32 getCurSliderValue() const { return getSliderValue(mCurSlider); }
void setCurSlider(const std::string& name);
void resetCurSlider();
void setCurSliderValue(F32 val, bool from_event = false) { setSliderValue(mCurSlider, val, from_event); }
/*virtual*/ void setValue(const LLSD& value) override;
/*virtual*/ LLSD getValue() const override { return mValue; }
boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb );
bool findUnusedValue(F32& initVal);
const std::string& addSlider();
const std::string& addSlider(F32 val);
bool addSlider(F32 val, const std::string& name);
void deleteSlider(const std::string& name);
void deleteCurSlider() { deleteSlider(mCurSlider); }
/*virtual*/ void clear() override;
/*virtual*/ bool handleHover(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask) override;
/*virtual*/ bool handleKeyHere(KEY key, MASK mask) override;
/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) override;
/*virtual*/ void draw() override;
S32 getMaxNumSliders() { return mMaxNumSliders; }
S32 getCurNumSliders() { return static_cast<S32>(mValue.size()); }
F32 getOverlapThreshold() { return mOverlapThreshold; }
bool canAddSliders() { return mValue.size() < mMaxNumSliders; }
protected:
LLSD mValue;
std::string mCurSlider;
std::string mHoverSlider;
static S32 mNameCounter;
S32 mMaxNumSliders;
bool mAllowOverlap;
bool mLoopOverlap;
F32 mOverlapThreshold;
bool mDrawTrack;
bool mUseTriangle; /// hacked in toggle to use a triangle
S32 mMouseOffset;
LLRect mDragStartThumbRect;
S32 mThumbWidth;
std::map<std::string, LLRect>
mThumbRects;
LLUIColor mTrackColor;
LLUIColor mThumbOutlineColor;
LLUIColor mThumbHighlightColor;
LLUIColor mThumbCenterColor;
LLUIColor mThumbCenterSelectedColor;
LLUIColor mDisabledThumbColor;
LLUIColor mTriangleColor;
LLUIImagePtr mThumbImagep; //blimps on the slider, for now no 'disabled' support
LLUIImagePtr mRoundedSquareImgp; //blimps on the slider, for now no 'disabled' support
const EOrientation mOrientation;
commit_signal_t* mMouseDownSignal;
commit_signal_t* mMouseUpSignal;
};
#endif // LL_MULTI_SLIDER_H
+525
View File
@@ -0,0 +1,525 @@
/**
* @file llmultisliderctrl.cpp
* @brief LLMultiSliderCtrl base class
*
* $LicenseInfo:firstyear=2007&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$
*/
#include "linden_common.h"
#include "llmultisliderctrl.h"
#include "llmath.h"
#include "llfontgl.h"
#include "llgl.h"
#include "llkeyboard.h"
#include "lllineeditor.h"
#include "llmultislider.h"
#include "llstring.h"
#include "lltextbox.h"
#include "llui.h"
#include "lluiconstants.h"
#include "llcontrol.h"
#include "llfocusmgr.h"
#include "llresmgr.h"
#include "lluictrlfactory.h"
static LLDefaultChildRegistry::Register<LLMultiSliderCtrl> r("multi_slider");
const U32 MAX_STRING_LENGTH = 10;
LLMultiSliderCtrl::Params::Params()
: text_width("text_width"),
label_width("label_width"),
show_text("show_text", true),
can_edit_text("can_edit_text", false),
max_sliders("max_sliders", 1),
allow_overlap("allow_overlap", false),
loop_overlap("loop_overlap", false),
orientation("orientation"),
thumb_image("thumb_image"),
thumb_width("thumb_width"),
thumb_highlight_color("thumb_highlight_color"),
overlap_threshold("overlap_threshold", 0),
draw_track("draw_track", true),
use_triangle("use_triangle", false),
decimal_digits("decimal_digits", 3),
text_color("text_color"),
text_disabled_color("text_disabled_color"),
mouse_down_callback("mouse_down_callback"),
mouse_up_callback("mouse_up_callback"),
sliders("slider")
{
mouse_opaque = true;
}
LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
: LLF32UICtrl(p),
mLabelBox( NULL ),
mEditor( NULL ),
mTextBox( NULL ),
mTextEnabledColor(p.text_color()),
mTextDisabledColor(p.text_disabled_color())
{
static LLUICachedControl<S32> multi_sliderctrl_spacing ("UIMultiSliderctrlSpacing", 0);
S32 top = getRect().getHeight();
S32 bottom = 0;
S32 left = 0;
S32 label_width = p.label_width;
S32 text_width = p.text_width;
// Label
if( !p.label().empty() )
{
if (p.label_width == 0)
{
label_width = p.font()->getWidth(p.label);
}
LLRect label_rect( left, top, label_width, bottom );
LLTextBox::Params params;
params.name("MultiSliderCtrl Label");
params.rect(label_rect);
params.initial_value(p.label());
params.font(p.font);
mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
addChild(mLabelBox);
}
S32 slider_right = getRect().getWidth();
if (p.show_text)
{
if (!p.text_width.isProvided())
{
text_width = 0;
// calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
if ( p.max_value() )
text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10 ( p.max_value ) ) + p.decimal_digits + 1 );
if ( p.increment < 1.0f )
text_width += p.font()->getWidth(std::string(".")); // (mostly) take account of decimal point in value
if ( p.min_value < 0.0f || p.max_value < 0.0f )
text_width += p.font()->getWidth(std::string("-")); // (mostly) take account of minus sign
// padding to make things look nicer
text_width += 8;
}
S32 text_left = getRect().getWidth() - text_width;
slider_right = text_left - multi_sliderctrl_spacing;
LLRect text_rect( text_left, top, getRect().getWidth(), bottom );
if( p.can_edit_text )
{
LLLineEditor::Params params;
params.name("MultiSliderCtrl Editor");
params.rect(text_rect);
params.font(p.font);
params.max_length.bytes(MAX_STRING_LENGTH);
params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit);
params.prevalidator(&LLTextValidate::validateFloat);
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) );
// don't do this, as selecting the entire text is single clicking in some cases
// and double clicking in others
//mEditor->setSelectAllonFocusReceived(true);
addChild(mEditor);
}
else
{
LLTextBox::Params params;
params.name("MultiSliderCtrl Text");
params.rect(text_rect);
params.font(p.font);
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
mTextBox = LLUICtrlFactory::create<LLTextBox> (params);
addChild(mTextBox);
}
}
S32 slider_left = label_width ? label_width + multi_sliderctrl_spacing : 0;
LLRect slider_rect( slider_left, top, slider_right, bottom );
LLMultiSlider::Params params;
params.sliders = p.sliders;
params.rect(slider_rect);
params.commit_callback.function( LLMultiSliderCtrl::onSliderCommit );
params.mouse_down_callback( p.mouse_down_callback );
params.mouse_up_callback( p.mouse_up_callback );
params.initial_value(p.initial_value());
params.min_value(p.min_value);
params.max_value(p.max_value);
params.increment(p.increment);
params.max_sliders(p.max_sliders);
params.allow_overlap(p.allow_overlap);
params.loop_overlap(p.loop_overlap);
if (p.overlap_threshold.isProvided())
{
params.overlap_threshold = p.overlap_threshold;
}
params.orientation(p.orientation);
params.thumb_image(p.thumb_image);
params.thumb_highlight_color(p.thumb_highlight_color);
if (p.thumb_width.isProvided())
{
// otherwise should be provided by template
params.thumb_width(p.thumb_width);
}
params.draw_track(p.draw_track);
params.use_triangle(p.use_triangle);
params.control_name(p.control_name);
mMultiSlider = LLUICtrlFactory::create<LLMultiSlider> (params);
addChild( mMultiSlider );
mCurValue = mMultiSlider->getCurSliderValue();
updateText();
}
LLMultiSliderCtrl::~LLMultiSliderCtrl()
{
// Children all cleaned up by default view destructor.
}
// static
void LLMultiSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
{
LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
llassert( caller == self->mEditor );
self->onFocusReceived();
}
void LLMultiSliderCtrl::setValue(const LLSD& value)
{
mMultiSlider->setValue(value);
mCurValue = mMultiSlider->getCurSliderValue();
updateText();
}
void LLMultiSliderCtrl::setSliderValue(const std::string& name, F32 v, bool from_event)
{
mMultiSlider->setSliderValue(name, v, from_event );
mCurValue = mMultiSlider->getCurSliderValue();
updateText();
}
void LLMultiSliderCtrl::setCurSlider(const std::string& name)
{
mMultiSlider->setCurSlider(name);
mCurValue = mMultiSlider->getCurSliderValue();
}
void LLMultiSliderCtrl::resetCurSlider()
{
mMultiSlider->resetCurSlider();
}
bool LLMultiSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit& text )
{
bool res = false;
if (mLabelBox)
{
res = mLabelBox->setTextArg(key, text);
if (res && mLabelWidth == 0)
{
S32 label_width = mFont->getWidth(mLabelBox->getWText().c_str());
LLRect rect = mLabelBox->getRect();
S32 prev_right = rect.mRight;
rect.mRight = rect.mLeft + label_width;
mLabelBox->setRect(rect);
S32 delta = rect.mRight - prev_right;
rect = mMultiSlider->getRect();
S32 left = rect.mLeft + delta;
static LLUICachedControl<S32> multi_slider_ctrl_spacing ("UIMultiSliderctrlSpacing", 0);
left = llclamp(left, 0, rect.mRight - multi_slider_ctrl_spacing);
rect.mLeft = left;
mMultiSlider->setRect(rect);
}
}
return res;
}
const std::string& LLMultiSliderCtrl::addSlider()
{
const std::string& name = mMultiSlider->addSlider();
// if it returns null, pass it on
if(name == LLStringUtil::null) {
return LLStringUtil::null;
}
// otherwise, update stuff
mCurValue = mMultiSlider->getCurSliderValue();
updateText();
return name;
}
const std::string& LLMultiSliderCtrl::addSlider(F32 val)
{
const std::string& name = mMultiSlider->addSlider(val);
// if it returns null, pass it on
if(name == LLStringUtil::null) {
return LLStringUtil::null;
}
// otherwise, update stuff
mCurValue = mMultiSlider->getCurSliderValue();
updateText();
return name;
}
bool LLMultiSliderCtrl::addSlider(F32 val, const std::string& name)
{
bool res = mMultiSlider->addSlider(val, name);
if (res)
{
mCurValue = mMultiSlider->getCurSliderValue();
updateText();
}
return res;
}
void LLMultiSliderCtrl::deleteSlider(const std::string& name)
{
mMultiSlider->deleteSlider(name);
mCurValue = mMultiSlider->getCurSliderValue();
updateText();
}
void LLMultiSliderCtrl::clear()
{
setCurSliderValue(0.0f);
if( mEditor )
{
mEditor->setText(std::string(""));
}
if( mTextBox )
{
mTextBox->setText(std::string(""));
}
// get rid of sliders
mMultiSlider->clear();
}
bool LLMultiSliderCtrl::isMouseHeldDown()
{
return gFocusMgr.getMouseCapture() == mMultiSlider;
}
void LLMultiSliderCtrl::updateText()
{
if( mEditor || mTextBox )
{
LLLocale locale(LLLocale::USER_LOCALE);
// Don't display very small negative values as -0.000
F32 displayed_value = (F32)(floor(getCurSliderValue() * pow(10.0, (F64)mPrecision) + 0.5) / pow(10.0, (F64)mPrecision));
std::string format = llformat("%%.%df", mPrecision);
std::string text = llformat(format.c_str(), displayed_value);
if( mEditor )
{
mEditor->setText( text );
}
else
{
mTextBox->setText( text );
}
}
}
// static
void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata)
{
llassert(ctrl);
if (!ctrl)
return;
LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent());
llassert(self);
if (!self) // cast failed - wrong type! :O
return;
bool success = false;
F32 val = self->mCurValue;
F32 saved_val = self->mCurValue;
std::string text = self->mEditor->getText();
if( LLLineEditor::postvalidateFloat( text ) )
{
LLLocale locale(LLLocale::USER_LOCALE);
val = (F32) atof( text.c_str() );
if( self->mMultiSlider->getMinValue() <= val && val <= self->mMultiSlider->getMaxValue() )
{
self->setCurSliderValue( val ); // set the value temporarily so that the callback can retrieve it.
if( !self->mValidateSignal || (*(self->mValidateSignal))( self, val ) )
{
success = true;
}
}
}
if( success )
{
self->onCommit();
}
else
{
if( self->getCurSliderValue() != saved_val )
{
self->setCurSliderValue( saved_val );
}
self->reportInvalidData();
}
self->updateText();
}
// static
void LLMultiSliderCtrl::onSliderCommit(LLUICtrl* ctrl, const LLSD& userdata)
{
LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl->getParent());
if (!self)
return;
bool success = false;
F32 saved_val = self->mCurValue;
F32 new_val = self->mMultiSlider->getCurSliderValue();
self->mCurValue = new_val; // set the value temporarily so that the callback can retrieve it.
if( !self->mValidateSignal || (*(self->mValidateSignal))( self, new_val ) )
{
success = true;
}
if( success )
{
self->onCommit();
}
else
{
if( self->mCurValue != saved_val )
{
self->setCurSliderValue( saved_val );
}
self->reportInvalidData();
}
self->updateText();
}
void LLMultiSliderCtrl::setEnabled(bool b)
{
LLF32UICtrl::setEnabled( b );
if( mLabelBox )
{
mLabelBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
}
mMultiSlider->setEnabled( b );
if( mEditor )
{
mEditor->setEnabled( b );
}
if( mTextBox )
{
mTextBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
}
}
void LLMultiSliderCtrl::setTentative(bool b)
{
if( mEditor )
{
mEditor->setTentative(b);
}
LLF32UICtrl::setTentative(b);
}
void LLMultiSliderCtrl::onCommit()
{
setTentative(false);
if( mEditor )
{
mEditor->setTentative(false);
}
setControlValue(getValueF32());
LLF32UICtrl::onCommit();
}
void LLMultiSliderCtrl::setPrecision(S32 precision)
{
if (precision < 0 || precision > 10)
{
LL_ERRS() << "LLMultiSliderCtrl::setPrecision - precision out of range" << LL_ENDL;
return;
}
mPrecision = precision;
updateText();
}
boost::signals2::connection LLMultiSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
{
return mMultiSlider->setMouseDownCallback( cb );
}
boost::signals2::connection LLMultiSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
{
return mMultiSlider->setMouseUpCallback( cb );
}
void LLMultiSliderCtrl::onTabInto()
{
if( mEditor )
{
mEditor->onTabInto();
}
LLF32UICtrl::onTabInto();
}
void LLMultiSliderCtrl::reportInvalidData()
{
make_ui_sound("UISndBadKeystroke");
}
// virtual
void LLMultiSliderCtrl::setControlName(const std::string& control_name, LLView* context)
{
mMultiSlider->setControlName(control_name, context);
}
+174
View File
@@ -0,0 +1,174 @@
/**
* @file llmultisliderctrl.h
* @brief LLMultiSliderCtrl base class
*
* $LicenseInfo:firstyear=2007&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_MULTI_SLIDERCTRL_H
#define LL_MULTI_SLIDERCTRL_H
#include "llf32uictrl.h"
#include "v4color.h"
#include "llmultislider.h"
#include "lltextbox.h"
#include "llrect.h"
//
// Classes
//
class LLFontGL;
class LLLineEditor;
class LLSlider;
class LLMultiSliderCtrl : public LLF32UICtrl
{
public:
struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params>
{
Optional<S32> label_width,
text_width;
Optional<bool> show_text,
can_edit_text;
Optional<S32> decimal_digits,
thumb_width;
Optional<S32> max_sliders;
Optional<bool> allow_overlap,
loop_overlap,
draw_track,
use_triangle;
Optional<std::string> orientation,
thumb_image;
Optional<F32> overlap_threshold;
Optional<LLUIColor> text_color,
text_disabled_color,
thumb_highlight_color;
Optional<CommitCallbackParam> mouse_down_callback,
mouse_up_callback;
Multiple<LLMultiSlider::SliderParams> sliders;
Params();
};
protected:
LLMultiSliderCtrl(const Params&);
friend class LLUICtrlFactory;
public:
virtual ~LLMultiSliderCtrl();
F32 getSliderValue(const std::string& name) const { return mMultiSlider->getSliderValue(name); }
void setSliderValue(const std::string& name, F32 v, bool from_event = false);
virtual void setValue(const LLSD& value );
virtual LLSD getValue() const { return mMultiSlider->getValue(); }
virtual bool setLabelArg( const std::string& key, const LLStringExplicit& text );
const std::string& getCurSlider() const { return mMultiSlider->getCurSlider(); }
F32 getCurSliderValue() const { return mCurValue; }
void setCurSlider(const std::string& name);
void resetCurSlider();
void setCurSliderValue(F32 val, bool from_event = false) { setSliderValue(mMultiSlider->getCurSlider(), val, from_event); }
virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); }
virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); }
bool isMouseHeldDown();
virtual void setEnabled( bool b );
virtual void clear();
virtual void setPrecision(S32 precision);
void setMinValue(F32 min_value) {mMultiSlider->setMinValue(min_value);}
void setMaxValue(F32 max_value) {mMultiSlider->setMaxValue(max_value);}
void setIncrement(F32 increment) {mMultiSlider->setIncrement(increment);}
F32 getNearestIncrement(F32 value) const { return mMultiSlider->getNearestIncrement(value); }
F32 getSliderValueFromPos(S32 x, S32 y) const { return mMultiSlider->getSliderValueFromPos(x, y); }
LLRect getSliderThumbRect(const std::string &name) const { return mMultiSlider->getSliderThumbRect(name); }
void setSliderThumbImage(const std::string &name) { mMultiSlider->setSliderThumbImage(name); }
void clearSliderThumbImage() { mMultiSlider->clearSliderThumbImage(); }
/// for adding and deleting sliders
const std::string& addSlider();
const std::string& addSlider(F32 val);
bool addSlider(F32 val, const std::string& name);
void deleteSlider(const std::string& name);
void deleteCurSlider() { deleteSlider(mMultiSlider->getCurSlider()); }
F32 getMinValue() const { return mMultiSlider->getMinValue(); }
F32 getMaxValue() const { return mMultiSlider->getMaxValue(); }
S32 getMaxNumSliders() { return mMultiSlider->getMaxNumSliders(); }
S32 getCurNumSliders() { return mMultiSlider->getCurNumSliders(); }
F32 getOverlapThreshold() { return mMultiSlider->getOverlapThreshold(); }
bool canAddSliders() { return mMultiSlider->canAddSliders(); }
void setLabel(const std::string& label) { if (mLabelBox) mLabelBox->setText(label); }
void setLabelColor(const LLUIColor& c) { mTextEnabledColor = c; }
void setDisabledLabelColor(const LLUIColor& c) { mTextDisabledColor = c; }
boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
virtual void onTabInto();
virtual void setTentative(bool b); // marks value as tentative
virtual void onCommit(); // mark not tentative, then commit
virtual void setControlName(const std::string& control_name, LLView* context);
static void onSliderCommit(LLUICtrl* caller, const LLSD& userdata);
static void onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata);
static void onEditorGainFocus(LLFocusableElement* caller, void *userdata);
static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
private:
void updateText();
void reportInvalidData();
private:
const LLFontGL* mFont;
bool mShowText;
bool mCanEditText;
S32 mPrecision;
LLTextBox* mLabelBox;
S32 mLabelWidth;
F32 mCurValue;
LLMultiSlider* mMultiSlider;
LLLineEditor* mEditor;
LLTextBox* mTextBox;
LLUIColor mTextEnabledColor;
LLUIColor mTextDisabledColor;
};
#endif // LL_MULTI_SLIDERCTRL_H
+34
View File
@@ -0,0 +1,34 @@
/**
* @file llnotificationptr.h
*
* $LicenseInfo:firstyear=2008&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 LLNOTIFICATIONPTR_H
#define LLNOTIFICATIONPTR_H
// Many classes just store a single LLNotificationPtr
// and llnotifications.h is very large, so define this ligher header.
class LLNotification;
typedef std::shared_ptr<LLNotification> LLNotificationPtr;
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More