diff --git a/.gitignore b/.gitignore
index f94d376ae5..5fa4a04a62 100755
--- a/.gitignore
+++ b/.gitignore
@@ -107,4 +107,4 @@ my_autobuild.xml
compile_commands.json
# ignore tracy for now
-indra/tracy
\ No newline at end of file
+indra/tracy
diff --git a/autobuild.xml b/autobuild.xml
index 3fa8fe8865..0c2b1db6b7 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -261,6 +261,36 @@
version
1.2.15
+ Tracy
+
apr_suite
copyright
@@ -796,9 +826,9 @@
archive
hash
- 7599bb6b05a5e48ce78180735e5d3355
+ 9a586d333b3c35389b29c7e8c7ebcc8f
url
- http://3p.firestormviewer.org/dullahan-1.8.0.202007261348_81.3.10_gb223419_chromium-81.0.4044.138-windows-202081313.tar.bz2
+ http://3p.firestormviewer.org/dullahan-1.8.0.202011211324_81.3.10_gb223419_chromium-81.0.4044.138-windows-203261227.tar.bz2
name
windows
@@ -808,9 +838,9 @@
archive
hash
- 92ced00cd0f89d0154ce2bcc6da086e0
+ 698e79226d0fb3b935509769a36bffd4
url
- http://3p.firestormviewer.org/dullahan-1.8.0.202007261348_81.3.10_gb223419_chromium-81.0.4044.138-windows64-202081325.tar.bz2
+ http://3p.firestormviewer.org/dullahan-1.8.0.202011211324_81.3.10_gb223419_chromium-81.0.4044.138-windows64-203261222.tar.bz2
name
windows64
@@ -1824,9 +1854,9 @@
archive
hash
- eba43dcfeb1c14aab25f588d9f625839
+ dce2cc624e216eb991412ec0c5538cf9
url
- file:///opt/firestorm/kdu-8.0.6-linux64-202302217.tar.bz2
+ file:///opt/firestorm/kdu-8.1-linux64-210652339.tar.bz2
name
linux64
@@ -1836,9 +1866,9 @@
archive
hash
- f5c682b490672aadf97ec9b938b351a9
+ 1cd284c85b5f05fff6b286e85b55ebf2
url
- file:///c:/cygwin/opt/firestorm/kdu-8.0.6-windows-202302209.tar.bz2
+ file:///c:/cygwin/opt/firestorm/kdu-8.1-windows-210862059.tar.bz2
name
windows
@@ -1848,9 +1878,9 @@
archive
hash
- f5c682b490672aadf97ec9b938b351a9
+ 1cd284c85b5f05fff6b286e85b55ebf2
url
- file:///c:/cygwin/opt/firestorm/kdu-8.0.6-windows-202302209.tar.bz2
+ file:///c:/cygwin/opt/firestorm/kdu-8.1-windows-210862059.tar.bz2
name
windows64
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index d8f6db9003..0c02ae3425 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -31,20 +31,20 @@ if (OPENSIM)
add_definitions(-DOPENSIM=1)
if (SINGLEGRID)
add_definitions(-DSINGLEGRID=1 -DSINGLEGRID_URI=\"${SINGLEGRID_URI}\")
- message("compiling with OpenSim support - Single Grid version (${SINGLEGRID_URI})")
+ message(STATUS "Compiling with OpenSim support - Single Grid version (${SINGLEGRID_URI})")
else (SINGLEGRID)
- message("compiling with OpenSim support")
+ message(STATUS "Compiling with OpenSim support")
endif (SINGLEGRID)
else (OPENSIM)
if (SINGLEGRID)
- message( WARNING "Value for SINGLEGRID is unused during Havok/SecondLife builds" )
+ message(WARNING "Value for SINGLEGRID is unused during Havok/SecondLife builds" )
endif()
- message("compiling without OpenSim support")
+ message(STATUS "Compiling without OpenSim support")
endif (OPENSIM)
if (HAVOK_TPV)
add_definitions(-DHAVOK_TPV=1)
- message("compiling with Havok libraries")
+ message(STATUS "Compiling with Havok libraries")
endif (HAVOK_TPV)
#
@@ -52,7 +52,7 @@ endif (HAVOK_TPV)
option(TESTBUILD "Generating test build" OFF)
if(TESTBUILD AND TESTBUILDPERIOD)
add_definitions(-DTESTBUILD=1 -DTESTBUILDPERIOD=${TESTBUILDPERIOD})
- message("creating test build version; test period: ${TESTBUILDPERIOD} days")
+ message(STATUS "Creating test build version; test period: ${TESTBUILDPERIOD} days")
endif(TESTBUILD AND TESTBUILDPERIOD)
#
@@ -64,18 +64,27 @@ if (USE_AVX_OPTIMIZATION)
message(FATAL_ERROR "You cannot use AVX and AVX2 at the same time!")
else (USE_AVX2_OPTIMIZATION)
add_definitions(-DUSE_AVX_OPTIMIZATION=1)
- message("compiling with AVX optimizations")
+ message(STATUS "Compiling with AVX optimizations")
endif (USE_AVX2_OPTIMIZATION)
elseif (USE_AVX2_OPTIMIZATION)
add_definitions(-DUSE_AVX2_OPTIMIZATION=1)
- message("compiling with AVX2 optimizations")
+ message(STATUS "Compiling with AVX2 optimizations")
else (USE_AVX_OPTIMIZATION)
- message("compiling without AVX optimizations")
+ message(STATUS "Compiling without AVX optimizations")
endif (USE_AVX_OPTIMIZATION)
# [AVX Optimization]
add_subdirectory(cmake)
+# Tracy Profiler support
+option(USE_TRACY_PROFILER "Tracy Profiler support" OFF)
+if (USE_TRACY_PROFILER)
+ message(STATUS "Compiling with Tracy profiler")
+else (USE_TRACY_PROFILER)
+ message(STATUS "Compiling without Tracy profiler")
+endif (USE_TRACY_PROFILER)
+# Tracy Profiler support
+
add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
add_subdirectory(${LIBS_OPEN_PREFIX}llappearance)
add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index ce8b396cc1..8e62e95bac 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -60,6 +60,15 @@ if (WINDOWS)
# Don't build DLLs.
set(BUILD_SHARED_LIBS OFF)
+ if( USE_COMPILERCACHE )
+ string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
+ string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+ string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_REELASE}")
+ string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
+ string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+ string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
+ endif()
+
# for "backwards compatibility", cmake sneaks in the Zm1000 option which royally
# screws incredibuild. this hack disables it.
# for details see: http://connect.microsoft.com/VisualStudio/feedback/details/368107/clxx-fatal-error-c1027-inconsistent-values-for-ym-between-creation-and-use-of-precompiled-headers
@@ -139,7 +148,6 @@ if (WINDOWS)
# /arch:SSE2
/fp:fast
)
-
# Nicky: x64 implies SSE2
if( ADDRESS_SIZE EQUAL 32 )
add_definitions( /arch:SSE2 )
diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake
index 86e42fa0ba..3406e5fd15 100644
--- a/indra/cmake/BuildVersion.cmake
+++ b/indra/cmake/BuildVersion.cmake
@@ -12,7 +12,7 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n
if (DEFINED ENV{revision})
set(VIEWER_VERSION_REVISION $ENV{revision})
- message("Revision (from environment): ${VIEWER_VERSION_REVISION}")
+ message(STATUS "Revision (from environment): ${VIEWER_VERSION_REVISION}")
elseif (DEFINED ENV{AUTOBUILD_BUILD_ID})
set(VIEWER_VERSION_REVISION $ENV{AUTOBUILD_BUILD_ID})
@@ -38,23 +38,23 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
- message("Revision (from hg) ${VIEWER_VERSION_REVISION}")
+ message(STATUS "Revision (from hg) ${VIEWER_VERSION_REVISION}")
else ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
- message("Revision not set (repository not found?); using 0")
+ message(STATUS "Revision not set (repository not found?); using 0")
set(VIEWER_VERSION_REVISION 0 )
endif ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$")
else (DEFINED MERCURIAL AND DEFINED SED)
- message("Revision not set: 'hg' or 'sed' not found; using 0")
+ message(STATUS "Revision not set: 'hg' or 'sed' not found; using 0")
set(VIEWER_VERSION_REVISION 0)
endif (DEFINED MERCURIAL AND DEFINED SED)
endif (DEFINED ENV{revision})
- message("Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
+ message(STATUS "Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}")
else ( EXISTS ${VIEWER_VERSION_BASE_FILE} )
message(SEND_ERROR "Cannot get viewer version from '${VIEWER_VERSION_BASE_FILE}'")
endif ( EXISTS ${VIEWER_VERSION_BASE_FILE} )
if ("${VIEWER_VERSION_REVISION}" STREQUAL "")
- message("Ultimate fallback, revision was blank or not set: will use 0")
+ message(STATUS "Ultimate fallback, revision was blank or not set: will use 0")
set(VIEWER_VERSION_REVISION 0)
endif ("${VIEWER_VERSION_REVISION}" STREQUAL "")
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 7819669385..74d32defea 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -86,6 +86,7 @@ set(cmake_SOURCE_FILES
PulseAudio.cmake
Python.cmake
TemplateCheck.cmake
+ Tracy.cmake
Tut.cmake
UI.cmake
UnixInstall.cmake
diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index 8900419f9b..8c209fdb7e 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -4,12 +4,21 @@ include(APR)
include(Boost)
include(EXPAT)
include(ZLIB)
+include(Tracy) # Tracy profiler
+# Add Tracy profiler support
+#set(LLCOMMON_INCLUDE_DIRS
+# ${LIBS_OPEN_DIR}/llcommon
+# ${APRUTIL_INCLUDE_DIR}
+# ${APR_INCLUDE_DIR}
+# )
set(LLCOMMON_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llcommon
${APRUTIL_INCLUDE_DIR}
${APR_INCLUDE_DIR}
+ ${TRACY_INCLUDE_DIR}
)
+#
set(LLCOMMON_SYSTEM_INCLUDE_DIRS
${Boost_INCLUDE_DIRS}
)
diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
new file mode 100644
index 0000000000..b3bfb6fc65
--- /dev/null
+++ b/indra/cmake/Tracy.cmake
@@ -0,0 +1,16 @@
+# Tracy Profiler support.
+if (USE_TRACY_PROFILER)
+ include(Prebuilt)
+ use_prebuilt_binary(Tracy)
+ if (WINDOWS)
+ # set(TRACY_LIBRARIES
+ # ${ARCH_PREBUILT_DIRS_RELEASE}/Tracy.lib
+ add_definitions(-DTRACY_ENABLE=1 -DTRACY_NO_FASTTIMERS -DWINVER=0x0601 )
+ set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy)
+ elseif (DARWIN)
+ message(FATAL_ERROR "Tracy is not yet implemented in FS for OSX.")
+ else (WINDOWS)
+ add_definitions(-DTRACY_ENABLE=1 -DTRACY_NO_FASTTIMERS )
+ set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy)
+ endif (WINDOWS)
+endif (USE_TRACY_PROFILER)
diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp
index 3790107fd1..259bea4b67 100644
--- a/indra/llaudio/llaudioengine_fmodstudio.cpp
+++ b/indra/llaudio/llaudioengine_fmodstudio.cpp
@@ -804,7 +804,7 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename)
return false;
}
- if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB))
+ if (!gDirUtilp->fileExists(filename))
{
// File not found, abort.
return false;
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index e24ac88849..66cb19479f 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -69,6 +69,7 @@ set(llcommon_SOURCE_FILES
llinitparam.cpp
llinitdestroyclass.cpp
llinstancetracker.cpp
+ llkeybind.cpp
llleap.cpp
llleaplistener.cpp
llliveappconfig.cpp
@@ -180,6 +181,7 @@ set(llcommon_HEADER_FILES
llinitdestroyclass.h
llinitparam.h
llinstancetracker.h
+ llkeybind.h
llkeythrottle.h
llleap.h
llleaplistener.h
@@ -254,6 +256,11 @@ set(llcommon_HEADER_FILES
)
# Add all nd* files. memory pool, intrinsics, ...
+# Tracy Profiler support
+list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp)
+if (USE_TRACY_PROFILER)
+ list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp)
+endif()
SET( llcommon_ND_SOURCE_FILES
nd/ndexceptions.cpp
diff --git a/indra/llcommon/fstelemetry.cpp b/indra/llcommon/fstelemetry.cpp
new file mode 100644
index 0000000000..c2bc80b66a
--- /dev/null
+++ b/indra/llcommon/fstelemetry.cpp
@@ -0,0 +1,31 @@
+/**
+ * @file fstelemetry.cpp
+ * @brief fstelemetry Telemetry abstraction for FS
+ *
+ * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$
+ * Phoenix Firestorm Viewer Source Code
+ * Copyright (C) 2021, The Phoenix Firestorm Project, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
+ * http://www.firestormviewer.org
+ * $/LicenseInfo$
+ */
+#include "fstelemetry.h"
+namespace FSTelemetry
+{
+ bool active{false};
+}
\ No newline at end of file
diff --git a/indra/llcommon/fstelemetry.h b/indra/llcommon/fstelemetry.h
new file mode 100644
index 0000000000..87ec75b00a
--- /dev/null
+++ b/indra/llcommon/fstelemetry.h
@@ -0,0 +1,69 @@
+#pragma once
+#ifndef FS_TELEMETRY_H_INCLUDED
+#define FS_TELEMETRY_H_INCLUDED
+/**
+ * @file fstelemetry.h
+ * @brief fstelemetry Telemetry abstraction for FS
+ *
+ * $LicenseInfo:firstyear=2021&license=fsviewerlgpl$
+ * Phoenix Firestorm Viewer Source Code
+ * Copyright (C) 2021, The Phoenix Firestorm Project, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
+ * http://www.firestormviewer.org
+ * $/LicenseInfo$
+ */
+
+// define a simple set of empty macros that allow us to build without the Tracy profiler installed in 3p
+// this is similar to the profiler abstraction used by LL but as they have no plans to release that any time soon we'll replace it
+// Just a minimal set at the moment will add locks/gpu/memory and other stuff later.
+
+// generic switch (in case we ever add others or incorporate commercial tools like RAD Games if LL were to share a license)
+// turn off in the else statement below.
+#define FS_HAS_TELEMETRY_SUPPORT
+
+#ifdef TRACY_ENABLE // (Tracy open source telemetry)
+#include "Tracy.hpp"
+
+#define FSZone ZoneNamed( ___tracy_scoped_zone, FSTelemetry::active)
+#define FSZoneN( name ) ZoneNamedN( ___tracy_scoped_zone, name, FSTelemetry::active)
+#define FSZoneC( color ) ZoneNamedC( ___tracy_scoped_zone, color, FSTelemetry::active)
+#define FSZoneNC( name, color ) ZoneNamedNC( ___tracy_scoped_zone, name, color, FSTelemetry::active)
+#define FSPlot( name, value ) TracyPlot( name, value)
+#define FSFrameMark FrameMark
+#define FSTelemetryIsConnected TracyIsConnected
+
+#else // (no telemetry)
+
+// No we don't want no stinkin' telemetry. move along
+#undef FS_HAS_TELEMETRY_SUPPORT
+
+#define FSZone
+#define FSZoneN( name )
+#define FSZoneC( color )
+#define FSZoneNC( name, color )
+#define FSPlot( name, value )
+#define FSFrameMark
+#define FSTelemetryIsConnected
+#endif // TRACY_ENABLE
+
+namespace FSTelemetry
+{
+ extern bool active;
+}
+
+#endif
\ No newline at end of file
diff --git a/indra/llcommon/fstracyclient.cpp b/indra/llcommon/fstracyclient.cpp
new file mode 100644
index 0000000000..f21c8fd197
--- /dev/null
+++ b/indra/llcommon/fstracyclient.cpp
@@ -0,0 +1,53 @@
+//
+// Tracy profiler
+// ----------------
+//
+// For fast integration, compile and
+// link with this source file (and none
+// other) in your executable (or in the
+// main DLL / shared object on multi-DLL
+// projects).
+//
+
+// Define TRACY_ENABLE to enable profiler.
+#include "common/TracySystem.cpp"
+
+#ifdef TRACY_ENABLE
+
+#ifdef LL_WINDOWS
+# pragma warning(push, 0)
+#endif
+
+#include "common/tracy_lz4.cpp"
+#include "client/TracyProfiler.cpp"
+#include "client/TracyCallstack.cpp"
+#include "client/TracySysTime.cpp"
+
+#include "client/TracySysTrace.cpp"
+
+#include "common/TracySocket.cpp"
+#include "client/tracy_rpmalloc.cpp"
+#include "client/TracyDxt1.cpp"
+
+#if TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6
+# include "libbacktrace/alloc.cpp"
+# include "libbacktrace/dwarf.cpp"
+# include "libbacktrace/fileline.cpp"
+# include "libbacktrace/mmapio.cpp"
+# include "libbacktrace/posix.cpp"
+# include "libbacktrace/sort.cpp"
+# include "libbacktrace/state.cpp"
+# if TRACY_HAS_CALLSTACK == 4
+# include "libbacktrace/macho.cpp"
+# else
+# include "libbacktrace/elf.cpp"
+# endif
+#endif
+
+#ifdef LL_WINDOWS
+# pragma comment(lib, "ws2_32.lib")
+# pragma comment(lib, "dbghelp.lib")
+# pragma warning(pop)
+#endif
+
+#endif
\ No newline at end of file
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index 65a937570f..937f1a5501 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -57,6 +57,17 @@ enum ETerrainBrushType
E_LANDBRUSH_INVALID = 6
};
+enum EMouseClickType{
+ CLICK_NONE = -1,
+ CLICK_LEFT = 0,
+ CLICK_MIDDLE,
+ CLICK_RIGHT,
+ CLICK_BUTTON4,
+ CLICK_BUTTON5,
+ CLICK_DOUBLELEFT,
+ CLICK_COUNT // 'size', CLICK_NONE does not counts
+};
+
// keys
// Bit masks for various keyboard modifier keys.
const MASK MASK_NONE = 0x0000;
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index ab93713b44..4f6afd17fd 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -60,7 +60,6 @@ namespace LLTrace
//////////////////////////////////////////////////////////////////////////////
// statics
-
bool BlockTimer::sLog = false;
std::string BlockTimer::sLogName = "";
bool BlockTimer::sMetricLog = false;
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index f3405ea993..2374483c73 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -38,7 +38,27 @@
#define LL_FAST_TIMER_ON 1
#define LL_FASTTIMER_USE_RDTSC 1
-#define LL_RECORD_BLOCK_TIME(timer_stat) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+// Add Tracy profiler support
+/*
+#define LL_RECORD_BLOCK_TIME(timer_stat) \
+const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+*/
+#include "fstelemetry.h"
+#ifdef TRACY_ENABLE
+// #undef TRACY_NO_FASTTIMERS // Uncomment if you want FASTTIMERS as well.
+#ifdef TRACY_NO_FASTTIMERS
+#define LL_RECORD_BLOCK_TIME(timer_stat) \
+FSZoneN( #timer_stat );
+#else // TRACY_NO_FASTTIMERS
+#define LL_RECORD_BLOCK_TIME(timer_stat) \
+FSZoneN( #timer_stat ); \
+const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+#endif // TRACY_NO_FASTTIMERS
+#else // TRACY_ENABLE
+#define LL_RECORD_BLOCK_TIME(timer_stat) \
+const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
+#endif // TRACY_ENABLE
+//
namespace LLTrace
{
diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
new file mode 100644
index 0000000000..38696c2258
--- /dev/null
+++ b/indra/llcommon/llkeybind.cpp
@@ -0,0 +1,395 @@
+/**
+ * @file llkeybind.cpp
+ * @brief Information about key combinations.
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2019, 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 "llkeybind.h"
+
+#include "llsd.h"
+#include "llsdutil.h"
+
+LLKeyData::LLKeyData()
+ :
+ mMouse(CLICK_NONE),
+ mKey(KEY_NONE),
+ mMask(MASK_NONE),
+ mIgnoreMasks(false)
+{
+}
+
+LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask)
+ :
+ mMouse(mouse),
+ mKey(key),
+ mMask(mask),
+ mIgnoreMasks(false)
+{
+}
+
+LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask)
+ :
+ mMouse(mouse),
+ mKey(key),
+ mMask(MASK_NONE),
+ mIgnoreMasks(ignore_mask)
+{
+}
+
+LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
+ :
+ mMouse(mouse),
+ mKey(key),
+ mMask(mask),
+ mIgnoreMasks(ignore_mask)
+{
+}
+
+LLKeyData::LLKeyData(const LLSD &key_data)
+{
+ if (key_data.has("mouse"))
+ {
+ mMouse = (EMouseClickType)key_data["mouse"].asInteger();
+ }
+ if (key_data.has("key"))
+ {
+ mKey = key_data["key"].asInteger();
+ }
+ if (key_data.has("ignore_accelerators"))
+ {
+ mIgnoreMasks = key_data["ignore_accelerators"];
+ }
+ if (key_data.has("mask"))
+ {
+ mMask = key_data["mask"].asInteger();
+ }
+}
+
+LLSD LLKeyData::asLLSD() const
+{
+ LLSD data;
+ data["mouse"] = (LLSD::Integer)mMouse;
+ data["key"] = (LLSD::Integer)mKey;
+ data["mask"] = (LLSD::Integer)mMask;
+ if (mIgnoreMasks)
+ {
+ data["ignore_accelerators"] = (LLSD::Boolean)mIgnoreMasks;
+ }
+ return data;
+}
+
+bool LLKeyData::isEmpty() const
+{
+ return mMouse == CLICK_NONE && mKey == KEY_NONE;
+}
+
+void LLKeyData::reset()
+{
+ mMouse = CLICK_NONE;
+ mKey = KEY_NONE;
+ mMask = MASK_NONE;
+ mIgnoreMasks = false;
+}
+
+LLKeyData& LLKeyData::operator=(const LLKeyData& rhs)
+{
+ mMouse = rhs.mMouse;
+ mKey = rhs.mKey;
+ mMask = rhs.mMask;
+ mIgnoreMasks = rhs.mIgnoreMasks;
+ return *this;
+}
+
+bool LLKeyData::operator==(const LLKeyData& rhs)
+{
+ if (mMouse != rhs.mMouse) return false;
+ if (mKey != rhs.mKey) return false;
+ if (mMask != rhs.mMask) return false;
+ if (mIgnoreMasks != rhs.mIgnoreMasks) return false;
+ return true;
+}
+
+bool LLKeyData::operator!=(const LLKeyData& rhs)
+{
+ if (mMouse != rhs.mMouse) return true;
+ if (mKey != rhs.mKey) return true;
+ if (mMask != rhs.mMask) return true;
+ if (mIgnoreMasks != rhs.mIgnoreMasks) return true;
+ return false;
+}
+
+bool LLKeyData::canHandle(const LLKeyData& data) const
+{
+ if (data.mKey == mKey
+ && data.mMouse == mMouse
+ && ((mIgnoreMasks && (data.mMask & mMask) == mMask) || data.mMask == mMask))
+ {
+ return true;
+ }
+ return false;
+}
+
+bool LLKeyData::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
+{
+ if (mouse == mMouse
+ && key == mKey
+ && ((mIgnoreMasks && (mask & mMask) == mMask) || mask == mMask))
+ {
+ return true;
+ }
+ return false;
+}
+
+// LLKeyBind
+
+LLKeyBind::LLKeyBind(const LLSD &key_bind)
+{
+ if (key_bind.isArray())
+ {
+ for (LLSD::array_const_iterator data = key_bind.beginArray(), endLists = key_bind.endArray();
+ data != endLists;
+ data++
+ )
+ {
+ mData.push_back(LLKeyData(*data));
+ }
+ }
+}
+
+bool LLKeyBind::operator==(const LLKeyBind& rhs)
+{
+ U32 size = mData.size();
+ if (size != rhs.mData.size()) return false;
+
+ for (U32 i = 0; i < size; i++)
+ {
+ if (mData[i] != rhs.mData[i]) return false;
+ }
+
+ return true;
+}
+
+bool LLKeyBind::operator!=(const LLKeyBind& rhs)
+{
+ U32 size = mData.size();
+ if (size != rhs.mData.size()) return true;
+
+ for (U32 i = 0; i < size; i++)
+ {
+ if (mData[i] != rhs.mData[i]) return true;
+ }
+
+ return false;
+}
+
+bool LLKeyBind::isEmpty() const
+{
+ for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
+ {
+ if (!iter->isEmpty()) return false;
+ }
+ return true;
+}
+
+LLSD LLKeyBind::asLLSD() const
+{
+ S32 last = mData.size() - 1;
+ while (mData[last].empty())
+ {
+ last--;
+ }
+
+ LLSD data;
+ for (S32 i = 0; i <= last; ++i)
+ {
+ // append even if empty to not affect visual representation
+ data.append(mData[i].asLLSD());
+ }
+ return data;
+}
+
+bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
+{
+ if (mouse == CLICK_NONE && key == KEY_NONE)
+ {
+ // assume placeholder
+ return false;
+ }
+
+ for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
+ {
+ if (iter->canHandle(mouse, key, mask))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool LLKeyBind::canHandleKey(KEY key, MASK mask) const
+{
+ return canHandle(CLICK_NONE, key, mask);
+}
+
+bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const
+{
+ return canHandle(mouse, KEY_NONE, mask);
+}
+
+bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const
+{
+ if (mouse != CLICK_NONE || key != KEY_NONE)
+ {
+ for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
+ {
+ if (iter->mKey == key
+ && iter->mMask == mask
+ && iter->mMouse == mouse
+ && iter->mIgnoreMasks == ignore)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool LLKeyBind::hasKeyData(const LLKeyData& data) const
+{
+ return hasKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks);
+}
+
+bool LLKeyBind::hasKeyData(U32 index) const
+{
+ return mData.size() > index;
+}
+
+S32 LLKeyBind::findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const
+{
+ if (mouse != CLICK_NONE || key != KEY_NONE)
+ {
+ for (S32 i = 0; i < mData.size(); ++i)
+ {
+ if (mData[i].mKey == key
+ && mData[i].mMask == mask
+ && mData[i].mMouse == mouse
+ && mData[i].mIgnoreMasks == ignore)
+ {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+S32 LLKeyBind::findKeyData(const LLKeyData& data) const
+{
+ return findKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks);
+}
+
+LLKeyData LLKeyBind::getKeyData(U32 index) const
+{
+ if (mData.size() > index)
+ {
+ return mData[index];
+ }
+ return LLKeyData();
+}
+
+bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore)
+{
+ if (!hasKeyData(mouse, key, mask, ignore))
+ {
+ mData.push_back(LLKeyData(mouse, key, mask, ignore));
+ return true;
+ }
+ return false;
+}
+
+bool LLKeyBind::addKeyData(const LLKeyData& data)
+{
+ if (!hasKeyData(data))
+ {
+ mData.push_back(data);
+ return true;
+ }
+ return false;
+}
+
+void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index)
+{
+ replaceKeyData(LLKeyData(mouse, key, mask, ignore), index);
+}
+
+void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index)
+{
+ if (!data.isEmpty())
+ {
+ // if both click and key are none (isEmpty()), we are inserting a placeholder, we don't want to reset anything
+ // otherwise reset identical key
+ for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++)
+ {
+ if (iter->mKey == data.mKey
+ && iter->mMouse == data.mMouse
+ && iter->mIgnoreMasks == data.mIgnoreMasks
+ && iter->mMask == data.mMask)
+ {
+ // Replacing only fully equal combinations even in case 'ignore' is set
+ // Reason: Simplicity and user might decide to do a 'move' command as W and Shift+Ctrl+W, and 'run' as Shift+W
+ iter->reset();
+ break;
+ }
+ }
+ }
+ if (mData.size() <= index)
+ {
+ mData.resize(index + 1);
+ }
+ mData[index] = data;
+}
+
+void LLKeyBind::resetKeyData(S32 index)
+{
+ if (mData.size() > index)
+ {
+ mData[index].reset();
+ }
+}
+
+void LLKeyBind::trimEmpty()
+{
+ S32 last = mData.size() - 1;
+ while (last >= 0 && mData[last].empty())
+ {
+ mData.erase(mData.begin() + last);
+ last--;
+ }
+}
+
+U32 LLKeyBind::getDataCount()
+{
+ return mData.size();
+}
+
diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h
new file mode 100644
index 0000000000..c6b4bd970f
--- /dev/null
+++ b/indra/llcommon/llkeybind.h
@@ -0,0 +1,106 @@
+/**
+ * @file llkeybind.h
+ * @brief Information about key combinations.
+ *
+ * $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_KEYBIND_H
+#define LL_KEYBIND_H
+
+#include "indra_constants.h"
+
+// KeyData - single key combination (mouse/mask/keyboard)
+class LL_COMMON_API LLKeyData
+{
+public:
+ LLKeyData();
+ LLKeyData(EMouseClickType mouse, KEY key, MASK mask);
+ LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask);
+ LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask);
+ LLKeyData(const LLSD &key_data);
+
+ LLSD asLLSD() const;
+ bool isEmpty() const;
+ bool empty() const { return isEmpty(); };
+ void reset();
+ LLKeyData& operator=(const LLKeyData& rhs);
+ bool operator==(const LLKeyData& rhs);
+ bool operator!=(const LLKeyData& rhs);
+
+ bool canHandle(const LLKeyData& data) const;
+ bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const;
+
+ EMouseClickType mMouse;
+ KEY mKey;
+ MASK mMask;
+ // Either to expect exact match or ignore not expected masks as long as expected mask-bit is present
+ bool mIgnoreMasks;
+};
+
+// One function can bind to multiple Key options
+class LLKeyBind
+{
+public:
+ LLKeyBind() {}
+ LLKeyBind(const LLSD &key_bind);
+
+ bool operator==(const LLKeyBind& rhs);
+ bool operator!=(const LLKeyBind& rhs);
+ bool isEmpty() const;
+ bool empty() const { return isEmpty(); };
+
+ LLSD asLLSD() const;
+
+ bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const;
+ bool canHandleKey(KEY key, MASK mask) const;
+ bool canHandleMouse(EMouseClickType mouse, MASK mask) const;
+
+ // contains specified combination
+ bool hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const;
+ bool hasKeyData(const LLKeyData& data) const;
+ bool hasKeyData(U32 index) const;
+
+ // index of contained LLKeyData
+ S32 findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const;
+ S32 findKeyData(const LLKeyData& data) const;
+
+ LLKeyData getKeyData(U32 index) const;
+
+ // these methods enshure there will be no repeats
+ bool addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore);
+ bool addKeyData(const LLKeyData& data);
+ void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index);
+ void replaceKeyData(const LLKeyData& data, U32 index);
+ void resetKeyData(S32 index);
+ void clear() { mData.clear(); }
+ // if there any empty LLKeyData in the end of the array, remove them
+ void trimEmpty();
+ U32 getDataCount();
+
+private:
+ typedef std::vector data_vector_t;
+ data_vector_t mData;
+};
+
+
+#endif // LL_KEYBIND_H
diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp
index c952cb2f1a..6d3b7511a5 100644
--- a/indra/llfilesystem/llfilesystem.cpp
+++ b/indra/llfilesystem/llfilesystem.cpp
@@ -57,6 +57,7 @@ LLFileSystem::~LLFileSystem()
// static
bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType file_type)
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
std::string id_str;
file_id.toString(id_str);
const std::string extra_info = "";
@@ -85,6 +86,7 @@ bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType fil
bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error /*= 0*/)
//
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
std::string id_str;
file_id.toString(id_str);
const std::string extra_info = "";
@@ -102,6 +104,7 @@ bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType fi
bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::EType old_file_type,
const LLUUID& new_file_id, const LLAssetType::EType new_file_type)
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
std::string old_id_str;
old_file_id.toString(old_id_str);
const std::string extra_info = "";
@@ -132,6 +135,7 @@ bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::ETyp
// static
S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type)
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
std::string id_str;
file_id.toString(id_str);
const std::string extra_info = "";
@@ -157,6 +161,7 @@ S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType fi
BOOL LLFileSystem::read(U8* buffer, S32 bytes)
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
BOOL success = TRUE;
std::string id;
@@ -215,16 +220,19 @@ BOOL LLFileSystem::read(U8* buffer, S32 bytes)
S32 LLFileSystem::getLastBytesRead()
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
return mBytesRead;
}
BOOL LLFileSystem::eof()
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
return mPosition >= getSize();
}
BOOL LLFileSystem::write(const U8* buffer, S32 bytes)
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
std::string id_str;
mFileID.toString(id_str);
const std::string extra_info = "";
@@ -334,6 +342,7 @@ BOOL LLFileSystem::write(const U8* buffer, S32 bytes)
BOOL LLFileSystem::seek(S32 offset, S32 origin)
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
if (-1 == origin)
{
origin = mPosition;
@@ -364,22 +373,26 @@ BOOL LLFileSystem::seek(S32 offset, S32 origin)
S32 LLFileSystem::tell() const
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
return mPosition;
}
S32 LLFileSystem::getSize()
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
return LLFileSystem::getFileSize(mFileID, mFileType);
}
S32 LLFileSystem::getMaxSize()
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
// offer up a huge size since we don't care what the max is
return INT_MAX;
}
BOOL LLFileSystem::rename(const LLUUID& new_id, const LLAssetType::EType new_type)
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
LLFileSystem::renameFile(mFileID, mFileType, new_id, new_type);
mFileID = new_id;
@@ -390,6 +403,7 @@ BOOL LLFileSystem::rename(const LLUUID& new_id, const LLAssetType::EType new_typ
BOOL LLFileSystem::remove()
{
+ FSZoneC(tracy::Color::Gold); // measure cache performance
LLFileSystem::removeFile(mFileID, mFileType);
return TRUE;
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index d9449db6ad..300a60c551 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -1121,7 +1121,7 @@ void set_default_colour_weights(kdu_params *siz)
}
// Fix image encoding for KDU >= 8.0.4
-#if KDU_MAJOR_VERSION >= 8 && KDU_MINOR_VERSION >= 0 && KDU_PATCH_VERSION >= 4
+#if (KDU_MAJOR_VERSION*10000 + KDU_MINOR_VERSION*100 + KDU_PATCH_VERSION) >= 80004
cod = siz->access_cluster(ENC_params);
assert(cod != NULL);
#endif
diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h
index d82189b5df..9de1159009 100644
--- a/indra/llkdu/llimagej2ckdu.h
+++ b/indra/llkdu/llimagej2ckdu.h
@@ -32,7 +32,7 @@
//
// KDU core header files
//
-#ifndef LL_WINDOWS
+#ifdef LL_DARWIN
#define KDU_NO_THREADS
#endif
diff --git a/indra/llkdu/llkdumem.h b/indra/llkdu/llkdumem.h
index 44757a4bfc..28164e157e 100644
--- a/indra/llkdu/llkdumem.h
+++ b/indra/llkdu/llkdumem.h
@@ -28,7 +28,7 @@
#define LL_LLKDUMEM_H
// Support classes for reading and writing from memory buffers in KDU
-#ifndef LL_WINDOWS
+#ifdef LL_DARWIN
#define KDU_NO_THREADS
#endif
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 952cd085ae..68f83c790c 100644
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -19,6 +19,7 @@ include(Python)
include(Tut)
include(Python)
include(JsonCpp)
+include(LLXML) # For accessing settings
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
@@ -26,6 +27,7 @@ include_directories(
${LLCOMMON_INCLUDE_DIRS}
${LLCOREHTTP_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
+ ${LLXML_INCLUDE_DIRS} # For accessing settings
${LLMESSAGE_INCLUDE_DIRS}
${LLFILESYSTEM_INCLUDE_DIRS}
${JSONCPP_INCLUDE_DIR}
@@ -217,6 +219,7 @@ target_link_libraries(
${LLCOMMON_LIBRARIES}
${LLFILESYSTEM_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${LLXML_LIBRARIES} # For accessing settings
${JSONCPP_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
@@ -235,6 +238,7 @@ target_link_libraries(
${LLCOMMON_LIBRARIES}
${LLFILESYSTEM_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${LLXML_LIBRARIES} # For accessing settings
${JSONCPP_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
@@ -265,6 +269,7 @@ if (LINUX)
${WINDOWS_LIBRARIES}
${LLFILESYSTEM_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${LLXML_LIBRARIES} # For accessing settings
${CURL_LIBRARIES}
${NGHTTP2_LIBRARIES}
${LLCOMMON_LIBRARIES}
@@ -281,6 +286,7 @@ else (LINUX)
${WINDOWS_LIBRARIES}
${LLFILESYSTEM_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${LLXML_LIBRARIES} # For accessing settings
${CURL_LIBRARIES}
${NGHTTP2_LIBRARIES}
${LLCOMMON_LIBRARIES}
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index 795860e9f7..d9f8d49b6d 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -48,8 +48,9 @@
#include
#include
-#include "../newview/lggcontactsets.h"
-#include "../llxml/llcontrol.h"
+
+#include "llcontrol.h" // Optional legacy name cache expiration
+
// Time-to-live for a temp cache entry.
const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0;
// Maximum time an unrefreshed cache entry is allowed.
@@ -213,13 +214,15 @@ void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &h
LLAvatarName av_name;
// Contact sets alias
- if (LGGContactSets::getInstance()->hasPseudonym(agent_id))
+ bool dn_removed;
+ std::string pseudonym;
+ if (mCustomNameCheckCallback && mCustomNameCheckCallback(agent_id, dn_removed, pseudonym))
{
LLSD info(row);
- info["is_display_name_default"] = LGGContactSets::getInstance()->hasDisplayNameRemoved(agent_id);
- info["display_name"] = LGGContactSets::getInstance()->hasDisplayNameRemoved(agent_id)
+ info["is_display_name_default"] = dn_removed;
+ info["display_name"] = dn_removed
? (info["legacy_first_name"].asString() + " " + info["legacy_last_name"].asString())
- : LGGContactSets::getInstance()->getPseudonym(agent_id);
+ : pseudonym;
av_name.fromLLSD(info);
}
else
@@ -647,13 +650,15 @@ bool LLAvatarNameCache::getName(const LLUUID& agent_id, LLAvatarName *av_name)
{
*av_name = it->second;
// Contact sets alias
- if (LGGContactSets::getInstance()->hasPseudonym(agent_id))
+ bool dn_removed;
+ std::string pseudonym;
+ if (mCustomNameCheckCallback && mCustomNameCheckCallback(agent_id, dn_removed, pseudonym))
{
LLSD info = av_name->asLLSD();
- info["is_display_name_default"] = LGGContactSets::getInstance()->hasDisplayNameRemoved(agent_id);
- info["display_name"] = LGGContactSets::getInstance()->hasDisplayNameRemoved(agent_id)
+ info["is_display_name_default"] = dn_removed;
+ info["display_name"] = dn_removed
? (info["legacy_first_name"].asString() + " " + info["legacy_last_name"].asString())
- : LGGContactSets::getInstance()->getPseudonym(agent_id);
+ : pseudonym;
av_name->fromLLSD(info);
}
// Contact sets alias
@@ -711,14 +716,15 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::getNameCallback(cons
LLSD test = av_name.asLLSD();
// Contact sets alias
- if (LGGContactSets::getInstance()->hasPseudonym(agent_id))
+ bool dn_removed;
+ std::string pseudonym;
+ if (mCustomNameCheckCallback && mCustomNameCheckCallback(agent_id, dn_removed, pseudonym))
{
- LL_DEBUGS("AvNameCache") << "DN cache hit via alias " << agent_id << LL_ENDL;
LLSD info = av_name.asLLSD();
- info["is_display_name_default"] = LGGContactSets::getInstance()->hasDisplayNameRemoved(agent_id);
- info["display_name"] = LGGContactSets::getInstance()->hasDisplayNameRemoved(agent_id)
+ info["is_display_name_default"] = dn_removed;
+ info["display_name"] = dn_removed
? (info["legacy_first_name"].asString() + " " + info["legacy_last_name"].asString())
- : LGGContactSets::getInstance()->getPseudonym(agent_id);
+ : pseudonym;
av_name.fromLLSD(info);
}
// Contact sets alias
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
index 9663981faf..6b7aecad87 100644
--- a/indra/llmessage/llavatarnamecache.h
+++ b/indra/llmessage/llavatarnamecache.h
@@ -44,6 +44,14 @@ public:
typedef boost::signals2::signal use_display_name_signal_t;
typedef boost::function account_name_changed_callback_t;
+ // Contact sets
+ typedef boost::function custom_name_check_callback_t;
+ void setCustomNameCheckCallback(custom_name_check_callback_t cb)
+ {
+ mCustomNameCheckCallback = cb;
+ }
+ //
+
// Import/export the name cache to file.
bool importFile(std::istream& istr);
void exportFile(std::ostream& ostr);
@@ -200,6 +208,9 @@ private:
// Time when unrefreshed cached names were checked last.
F64 mLastExpireCheck;
+
+ // Contact sets
+ custom_name_check_callback_t mCustomNameCheckCallback;
};
// Parse a cache-control header to get the max-age delta-seconds.
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index d774f9276d..548913ecaf 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -446,7 +446,7 @@ void LLModel::generateNormals(F32 angle_cutoff)
if (vol_face.mNumIndices > 65535)
{
- LL_WARNS() << "Too many vertices for normal generation to work." << LL_ENDL;
+ LL_WARNS("MESHSKININFO") << "Too many vertices for normal generation to work." << LL_ENDL;
continue;
}
@@ -1115,7 +1115,7 @@ bool LLModel::loadModel(std::istream& is)
{
if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
{
- LL_WARNS() << "Mesh header parse error. Not a valid mesh asset!" << LL_ENDL;
+ LL_WARNS("MESHSKININFO") << "Mesh header parse error. Not a valid mesh asset!" << LL_ENDL;
return false;
}
}
@@ -1147,7 +1147,7 @@ bool LLModel::loadModel(std::istream& is)
if (header[lod_name[lod]]["offset"].asInteger() == -1 ||
header[lod_name[lod]]["size"].asInteger() == 0 )
{ //cannot load requested LOD
- LL_WARNS() << "LoD data is invalid!" << LL_ENDL;
+ LL_WARNS("MESHSKININFO") << "LoD data is invalid!" << LL_ENDL;
return false;
}
@@ -1210,7 +1210,7 @@ bool LLModel::loadModel(std::istream& is)
}
else
{
- LL_WARNS() << "unpackVolumeFaces failed!" << LL_ENDL;
+ LL_WARNS("MESHSKININFO") << "unpackVolumeFaces failed!" << LL_ENDL;
}
return false;
@@ -1238,7 +1238,7 @@ bool LLModel::isMaterialListSubset( LLModel* ref )
if (!foundRef)
{
- LL_INFOS() << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL;
+ LL_INFOS("MESHSKININFO") << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL;
return false;
}
}
@@ -1274,7 +1274,7 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn
bool isASubset = isMaterialListSubset( ref );
if ( !isASubset )
{
- LL_INFOS()<<"Material of model is not a subset of reference."<= face.mNumVertices)
{
- LL_WARNS() << "Face has invalid index." << LL_ENDL;
+ LL_WARNS("MESHSKININFO") << "Face has invalid index." << LL_ENDL;
return false;
}
}
if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0)
{
- LL_WARNS() << "Face has invalid number of indices." << LL_ENDL;
+ LL_WARNS("MESHSKININFO") << "Face has invalid number of indices." << LL_ENDL;
return false;
}
@@ -1900,7 +1908,7 @@ bool validate_model(const LLModel* mdl)
{
if (mdl->getNumVolumeFaces() == 0)
{
- LL_WARNS() << "Model has no faces!" << LL_ENDL;
+ LL_WARNS("MESHSKININFO") << "Model has no faces!" << LL_ENDL;
return false;
}
@@ -1908,13 +1916,13 @@ bool validate_model(const LLModel* mdl)
{
if (mdl->getVolumeFace(i).mNumVertices == 0)
{
- LL_WARNS() << "Face has no vertices." << LL_ENDL;
+ LL_WARNS("MESHSKININFO") << "Face has no vertices." << LL_ENDL;
return false;
}
if (mdl->getVolumeFace(i).mNumIndices == 0)
{
- LL_WARNS() << "Face has no indices." << LL_ENDL;
+ LL_WARNS("MESHSKININFO") << "Face has no indices." << LL_ENDL;
return false;
}
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index fd6787a660..e113c08eae 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -1100,6 +1100,13 @@ LLFontGL* LLFontGL::getFontOCRA()
static LLFontGL* fontp = getFont(LLFontDescriptor("OCRA","Monospace",0));
return fontp;
}
+
+//static
+LLFontGL* LLFontGL::getFontCascadia()
+{
+ static LLFontGL* fontp = getFont(LLFontDescriptor("Cascadia", "Cascadia", 0));
+ return fontp;
+}
//
//static
@@ -1152,6 +1159,10 @@ LLFontGL* LLFontGL::getFontByName(const std::string& name)
{
return getFontMonospace();
}
+ else if (name == "Cascadia")
+ {
+ return getFontCascadia();
+ }
//
else
{
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index acc922b752..5b03fc67b1 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -193,6 +193,7 @@ public:
// Advanced script editor
static LLFontGL* getFontScripting();
static LLFontGL* getFontOCRA();
+ static LLFontGL* getFontCascadia();
//
static LLFontGL* getFontExtChar();
static LLFontGL* getFont(const LLFontDescriptor& desc);
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
index a8cdce95e9..18f4fc4271 100644
--- a/indra/llrender/llfontregistry.cpp
+++ b/indra/llrender/llfontregistry.cpp
@@ -169,6 +169,8 @@ LLFontDescriptor LLFontDescriptor::normalize() const
// Advanced script editor
if (new_size != s_template_string && new_size.empty() && findSubString(new_name,"Scripting"))
new_size = "Scripting";
+ if (new_size != s_template_string && new_size.empty() && findSubString(new_name, "Cascadia"))
+ new_size = "Cascadia";
//
if (new_size.empty())
new_size = "Medium";
diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp
index 727fbe850e..4b057fa62c 100644
--- a/indra/llui/llcontainerview.cpp
+++ b/indra/llui/llcontainerview.cpp
@@ -47,6 +47,10 @@ LLContainerView::LLContainerView(const LLContainerView::Params& p)
: LLView(p),
mShowLabel(p.show_label),
mLabel(p.label),
+ // Add background visible flag and color to container_view so we can have blank scrollview containers
+ mBackgroundVisible(p.background_visible),
+ mBackgroundColor(p.bg_color),
+ //
mDisplayChildren(p.display_children)
{
mScrollContainer = NULL;
@@ -111,10 +115,14 @@ BOOL LLContainerView::handleMouseUp(S32 x, S32 y, MASK mask)
void LLContainerView::draw()
{
+ // 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);
- gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
+ // 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
diff --git a/indra/llui/llcontainerview.h b/indra/llui/llcontainerview.h
index 99267d978a..48ec36a861 100644
--- a/indra/llui/llcontainerview.h
+++ b/indra/llui/llcontainerview.h
@@ -47,9 +47,17 @@ public:
Optional label;
Optional show_label;
Optional display_children;
+ // Add background visible flag and color to container_view so we can have blank scrollview containers
+ Optional background_visible;
+ Optional bg_color;
+ //
Params()
: label("label"),
show_label("show_label", FALSE),
+ // 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)),
+ //
display_children("display_children", TRUE)
{
changeDefault(mouse_opaque, false);
@@ -90,5 +98,9 @@ public:
protected:
BOOL mDisplayChildren;
std::string mLabel;
+ // Add background visible flag and color to container_view so we can have blank scrollview containers
+ bool mBackgroundVisible;
+ LLUIColor mBackgroundColor;
+ //
};
#endif // LL_CONTAINERVIEW_
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 2252f5f5dd..5cd3be4d69 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -223,6 +223,12 @@ LLSD LLMenuItemGL::getValue() const
return getLabel();
}
+//virtual
+bool LLMenuItemGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+ return (mAcceleratorKey == key) && (mAcceleratorMask == mask);
+}
+
//virtual
BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
{
@@ -284,13 +290,13 @@ BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask)
// This function checks to see if the accelerator key is already in use;
// if not, it will be added to the list
-BOOL LLMenuItemGL::addToAcceleratorList(std::list *listp)
+BOOL LLMenuItemGL::addToAcceleratorList(std::list *listp)
{
- LLKeyBinding *accelerator = NULL;
+ LLMenuKeyboardBinding *accelerator = NULL;
if (mAcceleratorKey != KEY_NONE)
{
- std::list::iterator list_it;
+ std::list::iterator list_it;
for (list_it = listp->begin(); list_it != listp->end(); ++list_it)
{
accelerator = *list_it;
@@ -314,7 +320,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list *listp)
}
if (!accelerator)
{
- accelerator = new LLKeyBinding;
+ accelerator = new LLMenuKeyboardBinding;
if (accelerator)
{
accelerator->mKey = mAcceleratorKey;
@@ -1038,6 +1044,11 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
return TRUE;
}
+bool LLMenuItemBranchGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+ return getBranch() && getBranch()->hasAccelerator(key, mask);
+}
+
BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
{
return getBranch() && getBranch()->handleAcceleratorKey(key, mask);
@@ -1045,7 +1056,7 @@ BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
// This function checks to see if the accelerator key is already in use;
// if not, it will be added to the list
-BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list *listp)
+BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list *listp)
{
LLMenuGL* branch = getBranch();
if (!branch)
@@ -3050,6 +3061,27 @@ void LLMenuGL::updateParent(LLView* parentp)
}
}
+bool LLMenuGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+ if (key == KEY_NONE)
+ {
+ return false;
+ }
+ // Note: checking this way because mAccelerators seems to be broken
+ // mAccelerators probably needs to be cleaned up or fixed
+ // It was used for dupplicate accelerator avoidance.
+ item_list_t::const_iterator item_iter;
+ for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
+ {
+ LLMenuItemGL* itemp = *item_iter;
+ if (itemp->hasAccelerator(key, mask))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask)
{
// don't handle if not enabled
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index e47dfd7523..8e805328b2 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -42,6 +42,13 @@
extern S32 MENU_BAR_HEIGHT;
extern S32 MENU_BAR_WIDTH;
+class LLMenuKeyboardBinding
+{
+public:
+ KEY mKey;
+ MASK mMask;
+};
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemGL
//
@@ -92,6 +99,7 @@ public:
/*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(); }
@@ -110,7 +118,7 @@ public:
virtual void setBriefItem(BOOL brief);
virtual BOOL isBriefItem() const;
- virtual BOOL addToAcceleratorList(std::list *listp);
+ virtual BOOL addToAcceleratorList(std::list *listp);
void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; }
BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; }
@@ -437,7 +445,8 @@ public:
/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
/*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(const std::string& name, BOOL recurse) const;
@@ -633,10 +642,11 @@ public:
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 *listp);
+ virtual BOOL addToAcceleratorList(std::list *listp);
// called to rebuild the draw label
virtual void buildDrawLabel( void );
@@ -809,7 +819,7 @@ private:
void checkMenuTrigger();
- std::list mAccelerators;
+ std::list mAccelerators;
BOOL mAltKeyTrigger;
};
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 8000efad0e..13839da400 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -50,6 +50,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_
{
cell = new LLScrollListDate(cell_p);
}
+ else if (cell_p.type() == "icontext")
+ {
+ cell = new LLScrollListIconText(cell_p);
+ }
else // default is "text"
{
cell = new LLScrollListText(cell_p);
@@ -168,7 +172,7 @@ U32 LLScrollListText::sCount = 0;
LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
: LLScrollListCell(p),
- mText(p.value().asString()),
+ mText(p.label.isProvided() ? p.label() : p.value().asString()),
mFont(p.font),
mColor(p.color),
mUseColor(p.color.isProvided()),
@@ -192,7 +196,7 @@ LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
void LLScrollListText::highlightText(S32 offset, S32 num_chars)
{
mHighlightOffset = offset;
- mHighlightCount = num_chars;
+ mHighlightCount = llmax(0, num_chars);
}
//virtual
@@ -292,11 +296,12 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
if (mHighlightCount > 0)
{
+ // Highlight text
S32 left = 0;
switch(mFontAlignment)
{
case LLFontGL::LEFT:
- left = mFont->getWidth(mText.getString(), 0, mHighlightOffset);
+ left = mFont->getWidth(mText.getString(), 1, mHighlightOffset);
break;
case LLFontGL::RIGHT:
left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX);
@@ -319,7 +324,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
switch(mFontAlignment)
{
case LLFontGL::LEFT:
- start_x = 0.f;
+ start_x = 1.f;
break;
case LLFontGL::RIGHT:
start_x = (F32)getWidth();
@@ -435,3 +440,139 @@ const LLSD LLScrollListDate::getValue() const
{
return mDate;
}
+
+//
+// LLScrollListIconText
+//
+LLScrollListIconText::LLScrollListIconText(const LLScrollListCell::Params& p)
+ : LLScrollListText(p),
+ mIcon(p.value().isUUID() ? LLUI::getUIImageByID(p.value().asUUID()) : LLUI::getUIImage(p.value().asString())),
+ mPad(4)
+{
+ mTextWidth = getWidth() - mPad /*padding*/ - mFont->getLineHeight();
+}
+
+LLScrollListIconText::~LLScrollListIconText()
+{
+}
+
+const LLSD LLScrollListIconText::getValue() const
+{
+ if (mIcon.isNull())
+ {
+ return LLStringUtil::null;
+ }
+ return mIcon->getName();
+}
+
+void LLScrollListIconText::setValue(const LLSD& value)
+{
+ if (value.isUUID())
+ {
+ // don't use default image specified by LLUUID::null, use no image in that case
+ LLUUID image_id = value.asUUID();
+ mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL);
+ }
+ else
+ {
+ std::string value_string = value.asString();
+ if (LLUUID::validate(value_string))
+ {
+ setValue(LLUUID(value_string));
+ }
+ else if (!value_string.empty())
+ {
+ mIcon = LLUI::getUIImage(value.asString());
+ }
+ else
+ {
+ mIcon = NULL;
+ }
+ }
+}
+
+void LLScrollListIconText::setWidth(S32 width)
+{
+ LLScrollListCell::setWidth(width);
+ // Assume that iamge height and width is identical to font height and width
+ mTextWidth = width - mPad /*padding*/ - mFont->getLineHeight();
+}
+
+
+void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const
+{
+ LLColor4 display_color;
+ if (mUseColor)
+ {
+ display_color = mColor;
+ }
+ else
+ {
+ display_color = color;
+ }
+
+ S32 icon_height = mFont->getLineHeight();
+ S32 icon_space = mIcon ? (icon_height + mPad) : 0;
+
+ if (mHighlightCount > 0)
+ {
+ S32 left = 0;
+ switch (mFontAlignment)
+ {
+ case LLFontGL::LEFT:
+ left = mFont->getWidth(mText.getString(), icon_space + 1, mHighlightOffset);
+ break;
+ case LLFontGL::RIGHT:
+ left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX) - icon_space;
+ break;
+ case LLFontGL::HCENTER:
+ left = (getWidth() - mFont->getWidth(mText.getString()) - icon_space) / 2;
+ break;
+ }
+ LLRect highlight_rect(left - 2,
+ mFont->getLineHeight() + 1,
+ left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1,
+ 1);
+ mRoundedRectImage->draw(highlight_rect, highlight_color);
+ }
+
+ // Try to draw the entire string
+ F32 right_x;
+ U32 string_chars = mText.length();
+ F32 start_text_x = 0.f;
+ S32 start_icon_x = 0;
+ switch (mFontAlignment)
+ {
+ case LLFontGL::LEFT:
+ start_text_x = icon_space + 1;
+ start_icon_x = 1;
+ break;
+ case LLFontGL::RIGHT:
+ start_text_x = (F32)getWidth();
+ start_icon_x = getWidth() - mFont->getWidth(mText.getString()) - icon_space;
+ break;
+ case LLFontGL::HCENTER:
+ F32 center = (F32)getWidth()* 0.5f;
+ start_text_x = center + ((F32)icon_space * 0.5f);
+ start_icon_x = center - (((F32)icon_space + mFont->getWidth(mText.getString())) * 0.5f);
+ break;
+ }
+ mFont->render(mText.getWString(), 0,
+ start_text_x, 0.f,
+ display_color,
+ mFontAlignment,
+ LLFontGL::BOTTOM,
+ 0,
+ LLFontGL::NO_SHADOW,
+ string_chars,
+ getTextWidth(),
+ &right_x,
+ TRUE);
+
+ if (mIcon)
+ {
+ mIcon->draw(start_icon_x, 0, icon_height, icon_height, mColor);
+ }
+}
+
+
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index d625ebddcc..19576fb247 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -59,7 +59,8 @@ public:
visible;
Optional userdata;
- Optional value;
+ Optional value; // state of checkbox, icon id/name, date
+ Optional label; // description or text
Optional tool_tip;
Optional font;
@@ -75,6 +76,7 @@ public:
enabled("enabled", true),
visible("visible", true),
value("value"),
+ label("label"),
tool_tip("tool_tip", ""),
font("font", LLFontGL::getFontSansSerifSmall()),
font_color("font_color", LLColor4::black),
@@ -152,11 +154,12 @@ public:
void setText(const LLStringExplicit& text);
void setFontStyle(const U8 font_style);
-private:
+protected:
LLUIString mText;
S32 mTextWidth;
const LLFontGL* mFont;
LLColor4 mColor;
+ LLColor4 mHighlightColor;
U8 mUseColor;
LLFontGL::HAlign mFontAlignment;
BOOL mVisible;
@@ -169,7 +172,7 @@ private:
};
/*
- * Cell displaying an image.
+ * Cell displaying an image. AT the moment, this is specifically UI image
*/
class LLScrollListIcon : public LLScrollListCell
{
@@ -223,4 +226,26 @@ private:
LLDate mDate;
};
+/*
+* Cell displaying icon and text.
+*/
+
+class LLScrollListIconText : public LLScrollListText
+{
+public:
+ LLScrollListIconText(const LLScrollListCell::Params& p);
+ /*virtual*/ ~LLScrollListIconText();
+ /*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const;
+ /*virtual*/ const LLSD getValue() const;
+ /*virtual*/ void setValue(const LLSD& value);
+
+
+ S32 getIconWidth() const;
+ /*virtual*/ void setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/
+
+private:
+ LLPointer mIcon;
+ S32 mPad;
+};
+
#endif
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 9cec673674..71b5340d11 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -117,6 +117,13 @@ struct SortScrollListItem
// LLScrollListCtrl
//---------------------------------------------------------------------------
+void LLScrollListCtrl::SelectionTypeNames::declareValues()
+{
+ declare("row", LLScrollListCtrl::ROW);
+ declare("cell", LLScrollListCtrl::CELL);
+ declare("header", LLScrollListCtrl::HEADER);
+}
+
LLScrollListCtrl::Contents::Contents()
: columns("column"),
rows("row")
@@ -130,9 +137,11 @@ LLScrollListCtrl::Params::Params()
has_border("draw_border"),
draw_heading("draw_heading"),
search_column("search_column", 0),
+ selection_type("selection_type", ROW),
sort_column("sort_column", -1),
sort_ascending("sort_ascending", true),
sort_lazily("sort_lazily", false), // FIRE-30732 deferred sort as a UI property
+ can_sort("can_sort", true),
persist_sort_order("persist_sort_order", false), // Persists sort order of scroll lists
primary_sort_only("primary_sort_only", false), // Option to only sort by one column
mouse_wheel_opaque("mouse_wheel_opaque", false),
@@ -170,8 +179,10 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
mCommitOnKeyboardMovement(p.commit_on_keyboard_movement),
mCommitOnSelectionChange(p.commit_on_selection_change),
mSelectionChanged(false),
+ mSelectionType(p.selection_type),
mNeedsScroll(false),
mCanSelect(true),
+ mCanSort(p.can_sort),
mColumnsDirty(false),
mMaxItemCount(INT_MAX),
mBorderThickness( 2 ),
@@ -932,7 +943,15 @@ BOOL LLScrollListCtrl::selectFirstItem()
{
if (!itemp->getSelected())
{
- selectItem(itemp);
+ switch (mSelectionType)
+ {
+ case CELL:
+ selectItem(itemp, 0);
+ break;
+ case HEADER:
+ case ROW:
+ selectItem(itemp, -1);
+ }
}
success = TRUE;
mOriginalSelection = 0;
@@ -1001,7 +1020,8 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
{
if( itemp->getEnabled() )
{
- selectItem(itemp, FALSE);
+ // TODO: support range selection for cells
+ selectItem(itemp, -1, FALSE);
success = TRUE;
}
}
@@ -1127,10 +1147,14 @@ void LLScrollListCtrl::clearHighlightedItems()
void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index)
{
- if (mHighlightedItem != target_index)
- {
- mHighlightedItem = target_index;
- }
+ if (mHighlightedItem != target_index)
+ {
+ if (mHighlightedItem >= 0 && mHighlightedItem < mItemList.size())
+ {
+ mItemList[mHighlightedItem]->setHoverCell(-1);
+ }
+ mHighlightedItem = target_index;
+ }
}
S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
@@ -1145,7 +1169,8 @@ S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
{
if (item->getEnabled() && (item->getUUID() == (*iditr)))
{
- selectItem(item,FALSE);
+ // TODO: support multiple selection for cells
+ selectItem(item, -1, FALSE);
++count;
break;
}
@@ -1224,7 +1249,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
{
if (prev_item)
{
- selectItem(prev_item, !extend_selection);
+ selectItem(prev_item, cur_item->getSelectedCell(), !extend_selection);
}
else
{
@@ -1268,7 +1293,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
{
if (next_item)
{
- selectItem(next_item, !extend_selection);
+ selectItem(next_item, cur_item->getSelectedCell(), !extend_selection);
}
else
{
@@ -1347,7 +1372,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen
bool found = NULL != item;
if(found)
{
- selectItem(item);
+ selectItem(item, -1);
}
if (mCommitOnSelectionChange)
@@ -1422,7 +1447,7 @@ BOOL LLScrollListCtrl::selectItemByStringMatch(const LLWString& target, bool pre
BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
if (select)
{
- selectItem(item);
+ selectItem(item, -1);
found = TRUE;
break;
}
@@ -1473,7 +1498,7 @@ BOOL LLScrollListCtrl::selectItemByStringMatch(const LLWString& target, bool pre
// find offset of matching text (might have leading whitespace)
S32 offset = item_label.find(target_trimmed);
cellp->highlightText(offset, target_trimmed.size());
- selectItem(item);
+ selectItem(item, -1);
found = TRUE;
break;
}
@@ -1568,7 +1593,7 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected)
{
if (selected)
{
- selectItem(item);
+ selectItem(item, -1);
}
else
{
@@ -1650,7 +1675,7 @@ void LLScrollListCtrl::drawItems()
S32 max_columns = 0;
- LLColor4 highlight_color = LLColor4::white;
+ LLColor4 highlight_color = LLColor4::white; // ex: text inside cells
static LLUICachedControl type_ahead_timeout ("TypeAheadTimeout", 0);
highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout(), 0.4f, 0.f);
@@ -1702,7 +1727,8 @@ void LLScrollListCtrl::drawItems()
max_columns = llmax(max_columns, item->getNumColumns());
LLColor4 fg_color;
- LLColor4 bg_color(LLColor4::transparent);
+ LLColor4 hover_color(LLColor4::transparent);
+ LLColor4 select_color(LLColor4::transparent);
if( mScrollLines <= line && line < mScrollLines + num_page_lines )
{
@@ -1711,45 +1737,45 @@ void LLScrollListCtrl::drawItems()
{
if(item->getHighlighted()) // if it's highlighted, average the colors
{
- bg_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
+ select_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
}
else // otherwise just select-highlight it
{
- bg_color = mBgSelectedColor.get();
+ select_color = mBgSelectedColor.get();
}
fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get());
}
- else if (mHighlightedItem == line && mCanSelect)
+ if (mHighlightedItem == line && mCanSelect)
{
if(item->getHighlighted()) // if it's highlighted, average the colors
{
- bg_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
+ hover_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
}
else // otherwise just hover-highlight it
{
- bg_color = mHoveredColor.get();
+ hover_color = mHoveredColor.get();
}
}
else if (item->getHighlighted())
{
- bg_color = mHighlightedColor.get();
+ hover_color = mHighlightedColor.get();
}
else
{
// Why no stripes in single columns? This should be decided by the skin. -Zi
if (mDrawStripes && (line % 2 == 0)) // && (max_columns > 1))
{
- bg_color = mBgStripeColor.get();
+ hover_color = mBgStripeColor.get();
}
}
if (!item->getEnabled())
{
- bg_color = mBgReadOnlyColor.get();
+ hover_color = mBgReadOnlyColor.get();
}
- item->draw(item_rect, fg_color % alpha, bg_color% alpha, highlight_color % alpha, mColumnPadding);
+ item->draw(item_rect, fg_color % alpha, hover_color% alpha, select_color% alpha, highlight_color % alpha, mColumnPadding);
cur_y -= mLineHeight;
}
@@ -1925,7 +1951,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
if (mLastSelected == NULL)
{
- selectItem(hit_item);
+ selectItem(hit_item, getColumnIndexFromOffset(x));
}
else
{
@@ -1955,7 +1981,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
// Fix for FS-specific people list (radar)
if (item == hit_item || item == lastSelected)
{
- selectItem(item, FALSE);
+ selectItem(item, getColumnIndexFromOffset(x), FALSE);
selecting = !selecting;
if (hit_item == lastSelected)
{
@@ -1965,7 +1991,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
}
if (selecting)
{
- selectItem(item, FALSE);
+ selectItem(item, getColumnIndexFromOffset(x), FALSE);
}
}
}
@@ -1980,7 +2006,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable))
{
- selectItem(hit_item, FALSE);
+ selectItem(hit_item, getColumnIndexFromOffset(x), FALSE);
}
else
{
@@ -1994,12 +2020,12 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
else
{
deselectAllItems(TRUE);
- selectItem(hit_item);
+ selectItem(hit_item, getColumnIndexFromOffset(x));
}
}
else
{
- selectItem(hit_item);
+ selectItem(hit_item, getColumnIndexFromOffset(x));
}
selection_changed = mSelectionChanged;
@@ -2420,8 +2446,29 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
{
LLScrollListItem* item = hitItem(x, y);
if (item)
- {
- mouseOverHighlightNthItem(getItemIndex(item));
+ {
+ mouseOverHighlightNthItem(getItemIndex(item));
+ switch (mSelectionType)
+ {
+ case CELL:
+ item->setHoverCell(getColumnIndexFromOffset(x));
+ break;
+ case HEADER:
+ {
+ S32 cell = getColumnIndexFromOffset(x);
+ if (cell > 0)
+ {
+ item->setHoverCell(cell);
+ }
+ else
+ {
+ item->setHoverCell(-1);
+ }
+ break;
+ }
+ case ROW:
+ break;
+ }
}
else
{
@@ -2469,6 +2516,58 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
handled = TRUE;
}
break;
+ case KEY_LEFT:
+ if (mAllowKeyboardMovement || hasFocus())
+ {
+ // TODO: support multi-select
+ LLScrollListItem *item = getFirstSelected();
+ if (item)
+ {
+ S32 cell = item->getSelectedCell();
+ switch (mSelectionType)
+ {
+ case CELL:
+ if (cell < mColumns.size()) cell++;
+ break;
+ case HEADER:
+ if (cell == -1) cell = 1;
+ else if (cell > 1 && cell < mColumns.size()) cell++; // skip header
+ break;
+ case ROW:
+ cell = -1;
+ break;
+ }
+ item->setSelectedCell(cell);
+ handled = TRUE;
+ }
+ }
+ break;
+ case KEY_RIGHT:
+ if (mAllowKeyboardMovement || hasFocus())
+ {
+ // TODO: support multi-select
+ LLScrollListItem *item = getFirstSelected();
+ if (item)
+ {
+ S32 cell = item->getSelectedCell();
+ switch (mSelectionType)
+ {
+ case CELL:
+ if (cell >= 0) cell--;
+ break;
+ case HEADER:
+ if (cell > 1) cell--;
+ else if (cell == 1) cell = -1; // skip header
+ break;
+ case ROW:
+ cell = -1;
+ break;
+ }
+ item->setSelectedCell(cell);
+ handled = TRUE;
+ }
+ }
+ break;
case KEY_PAGE_UP:
if (mAllowKeyboardMovement || hasFocus())
{
@@ -2777,7 +2876,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char)
{
- selectItem(item);
+ selectItem(item, -1);
mNeedsScroll = true;
cellp->highlightText(0, 1);
mSearchTimer.reset();
@@ -2829,7 +2928,7 @@ BOOL LLScrollListCtrl::isRepeatedChars(const LLWString& string) const
return TRUE;
}
-void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_item)
+void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select_single_item)
{
if (!itemp) return;
@@ -2848,6 +2947,18 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_it
deselectAllItems(TRUE);
}
itemp->setSelected(TRUE);
+ switch (mSelectionType)
+ {
+ case CELL:
+ itemp->setSelectedCell(cell);
+ break;
+ case HEADER:
+ itemp->setSelectedCell(cell <= 0 ? -1 : cell);
+ break;
+ case ROW:
+ itemp->setSelectedCell(-1);
+ break;
+ }
mLastSelected = itemp;
mSelectionChanged = true;
}
@@ -3125,7 +3236,7 @@ void LLScrollListCtrl::selectAll()
LLScrollListItem *itemp = *iter;
if( itemp->getEnabled() )
{
- selectItem(itemp, FALSE);
+ selectItem(itemp, -1, FALSE);
}
}
@@ -3302,6 +3413,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
LLScrollListCtrl *parent = info->mParentCtrl;
if (!parent) return;
+ if (!parent->mCanSort) return;
+
S32 column_index = info->mIndex;
LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
@@ -3666,7 +3779,7 @@ void LLScrollListCtrl::setFilterString(const std::string& str)
{
if (!isFiltered(*iter))
{
- selectItem(*iter);
+ selectItem(*iter, -1);
break;
}
}
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 9f8c93b6ad..af00f56db5 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -54,6 +54,18 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
public LLCtrlListInterface, public LLCtrlScrollInterface
{
public:
+ typedef enum e_selection_type
+ {
+ ROW, // default
+ CELL, // does not support multi-selection
+ HEADER, // when pointing to cells in column 0 will highlight whole row, otherwise cell, no multi-select
+ } ESelectionType;
+
+ struct SelectionTypeNames : public LLInitParam::TypeValuesHelper
+ {
+ static void declareValues();
+ };
+
struct Contents : public LLInitParam::Block
{
Multiple columns;
@@ -100,6 +112,8 @@ public:
commit_on_selection_change,
mouse_wheel_opaque;
+ Optional selection_type;
+
// display flags
Optional has_border,
draw_heading,
@@ -116,7 +130,8 @@ public:
// sort and search behavior
Optional search_column,
sort_column;
- Optional sort_ascending;
+ Optional sort_ascending,
+ can_sort; // whether user is allowed to sort
Optional sort_lazily; // FIRE-30732 deferred sort as a UI property
Optional persist_sort_order; // Persists sort order of scroll lists
Optional primary_sort_only; // Option to only sort by one column
@@ -466,7 +481,7 @@ private:
void updateLineHeightInsert(LLScrollListItem* item);
void reportInvalidInput();
BOOL isRepeatedChars(const LLWString& string) const;
- void selectItem(LLScrollListItem* itemp, BOOL single_select = TRUE);
+ void selectItem(LLScrollListItem* itemp, S32 cell, BOOL single_select = TRUE);
void deselectItem(LLScrollListItem* itemp);
void commitIfChanged();
BOOL setSort(S32 column, BOOL ascending);
@@ -495,9 +510,11 @@ private:
bool mCommitOnKeyboardMovement;
bool mCommitOnSelectionChange;
bool mSelectionChanged;
+ ESelectionType mSelectionType;
bool mNeedsScroll;
bool mMouseWheelOpaque;
bool mCanSelect;
+ bool mCanSort; // Whether user is allowed to sort
bool mDisplayColumnHeaders;
bool mColumnsDirty;
bool mColumnWidthsDirty;
diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp
index df22c88afb..51c615dd00 100644
--- a/indra/llui/llscrolllistitem.cpp
+++ b/indra/llui/llscrolllistitem.cpp
@@ -40,6 +40,8 @@
LLScrollListItem::LLScrollListItem( const Params& p )
: mSelected(FALSE),
mHighlighted(FALSE),
+ mHoverIndex(-1),
+ mSelectedIndex(-1),
mEnabled(p.enabled),
mUserdata(p.userdata),
mItemValue(p.value)
@@ -53,6 +55,28 @@ LLScrollListItem::~LLScrollListItem()
mColumns.clear();
}
+void LLScrollListItem::setSelected(BOOL b)
+{
+ mSelected = b;
+ mSelectedIndex = -1;
+}
+
+void LLScrollListItem::setHighlighted(BOOL b)
+{
+ mHighlighted = b;
+ mHoverIndex = -1;
+}
+
+void LLScrollListItem::setHoverCell(S32 cell)
+{
+ mHoverIndex = cell;
+}
+
+void LLScrollListItem::setSelectedCell(S32 cell)
+{
+ mSelectedIndex = cell;
+}
+
void LLScrollListItem::addColumn(const LLScrollListCell::Params& p)
{
mColumns.push_back(LLScrollListCell::create(p));
@@ -120,12 +144,21 @@ std::string LLScrollListItem::getContentsCSV() const
}
-void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
+void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& hover_color, const LLColor4& select_color, const LLColor4& highlight_color, S32 column_padding)
{
// draw background rect
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
LLRect bg_rect = rect;
- gl_rect_2d( bg_rect, bg_color );
+ if (mSelectedIndex < 0 && getSelected())
+ {
+ // Whole item is highlighted/selected
+ gl_rect_2d(bg_rect, select_color);
+ }
+ else if (mHoverIndex < 0)
+ {
+ // Whole item is highlighted/selected
+ gl_rect_2d(bg_rect, hover_color);
+ }
S32 cur_x = rect.mLeft;
S32 num_cols = getNumColumns();
@@ -141,6 +174,25 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const
{
LLUI::translate((F32) cur_x, (F32) rect.mBottom);
+ if (mSelectedIndex == cur_col)
+ {
+ // select specific cell
+ LLRect highlight_rect(0,
+ cell->getHeight(),
+ cell->getWidth(),
+ 0);
+ gl_rect_2d(highlight_rect, select_color);
+ }
+ else if (mHoverIndex == cur_col)
+ {
+ // highlight specific cell
+ LLRect highlight_rect(0,
+ cell->getHeight(),
+ cell->getWidth() ,
+ 0);
+ gl_rect_2d(highlight_rect, hover_color);
+ }
+
cell->draw( fg_color, highlight_color );
}
LLUI::popMatrix();
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index 13655b5873..d2c3dd7721 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -77,15 +77,21 @@ public:
virtual ~LLScrollListItem();
- void setSelected( BOOL b ) { mSelected = b; }
+ void setSelected( BOOL b );
BOOL getSelected() const { return mSelected; }
void setEnabled( BOOL b ) { mEnabled = b; }
BOOL getEnabled() const { return mEnabled; }
- void setHighlighted( BOOL b ) { mHighlighted = b; }
+ void setHighlighted( BOOL b );
BOOL getHighlighted() const { return mHighlighted; }
+ void setSelectedCell( S32 cell );
+ S32 getSelectedCell() const { return mSelectedIndex; }
+
+ void setHoverCell( S32 cell );
+ S32 getHoverCell() const { return mHoverIndex; }
+
void setUserdata( void* userdata ) { mUserdata = userdata; }
void* getUserdata() const { return mUserdata; }
@@ -107,14 +113,21 @@ public:
std::string getContentsCSV() const;
- virtual void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding);
+ virtual void draw(const LLRect& rect,
+ const LLColor4& fg_color,
+ const LLColor4& hover_color, // highlight/hover selection of whole item or cell
+ const LLColor4& select_color, // highlight/hover selection of whole item or cell
+ const LLColor4& highlight_color, // highlights contents of cells (ex: text)
+ S32 column_padding);
protected:
LLScrollListItem( const Params& );
private:
BOOL mSelected;
- BOOL mHighlighted;
+ BOOL mHighlighted;
+ S32 mHoverIndex;
+ S32 mSelectedIndex;
BOOL mEnabled;
void* mUserdata;
LLSD mItemValue;
diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp
index f6f6c3931c..5404ac50e5 100644
--- a/indra/llwindow/llkeyboard.cpp
+++ b/indra/llwindow/llkeyboard.cpp
@@ -327,7 +327,7 @@ BOOL LLKeyboard::keyFromString(const std::string& str, KEY *key)
// static
-std::string LLKeyboard::stringFromKey(KEY key)
+std::string LLKeyboard::stringFromKey(KEY key, bool translate)
{
std::string res = get_if_there(sKeysToNames, key, std::string());
if (res.empty())
@@ -338,16 +338,60 @@ std::string LLKeyboard::stringFromKey(KEY key)
res = std::string(buffer);
}
- LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
- if (trans != NULL)
+ if (translate)
{
- res = trans(res.c_str());
+ LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
+ if (trans != NULL)
+ {
+ res = trans(res.c_str());
+ }
}
return res;
}
+//static
+std::string LLKeyboard::stringFromAccelerator(MASK accel_mask)
+{
+ std::string res;
+ LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
+
+ if (trans == NULL)
+ {
+ LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL;
+ return res;
+ }
+
+ // Append any masks
+#ifdef LL_DARWIN
+ // Standard Mac names for modifier keys in menu equivalents
+ // We could use the symbol characters, but they only exist in certain fonts.
+ if (accel_mask & MASK_CONTROL)
+ {
+ if (accel_mask & MASK_MAC_CONTROL)
+ {
+ res.append(trans("accel-mac-control"));
+ }
+ else
+ {
+ res.append(trans("accel-mac-command")); // Symbol would be "\xE2\x8C\x98"
+ }
+ }
+ if (accel_mask & MASK_ALT)
+ res.append(trans("accel-mac-option")); // Symbol would be "\xE2\x8C\xA5"
+ if (accel_mask & MASK_SHIFT)
+ res.append(trans("accel-mac-shift")); // Symbol would be "\xE2\x8C\xA7"
+#else
+ if (accel_mask & MASK_CONTROL)
+ res.append(trans("accel-win-control"));
+ if (accel_mask & MASK_ALT)
+ res.append(trans("accel-win-alt"));
+ if (accel_mask & MASK_SHIFT)
+ res.append(trans("accel-win-shift"));
+#endif
+ return res;
+}
//static
std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key )
{
@@ -359,41 +403,7 @@ std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key )
return res;
}
- LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
-
- if( trans == NULL )
- {
- LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL;
- return res;
- }
-
- // Append any masks
-#ifdef LL_DARWIN
- // Standard Mac names for modifier keys in menu equivalents
- // We could use the symbol characters, but they only exist in certain fonts.
- if( accel_mask & MASK_CONTROL )
- {
- if ( accel_mask & MASK_MAC_CONTROL )
- {
- res.append( trans("accel-mac-control") );
- }
- else
- {
- res.append( trans("accel-mac-command") ); // Symbol would be "\xE2\x8C\x98"
- }
- }
- if( accel_mask & MASK_ALT )
- res.append( trans("accel-mac-option") ); // Symbol would be "\xE2\x8C\xA5"
- if( accel_mask & MASK_SHIFT )
- res.append( trans("accel-mac-shift") ); // Symbol would be "\xE2\x8C\xA7"
-#else
- if( accel_mask & MASK_CONTROL )
- res.append( trans("accel-win-control") );
- if( accel_mask & MASK_ALT )
- res.append( trans("accel-win-alt") );
- if( accel_mask & MASK_SHIFT )
- res.append( trans("accel-win-shift") );
-#endif
+ res.append(stringFromAccelerator(accel_mask));
std::string key_string = LLKeyboard::stringFromKey(key);
if ((accel_mask & MASK_NORMALKEYS) &&
(key_string[0] == '-' || key_string[0] == '=' || key_string[0] == '+'))
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index 6f2dc87317..36bd8bcbed 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -38,10 +38,10 @@ enum EKeystate
{
KEYSTATE_DOWN,
KEYSTATE_LEVEL,
- KEYSTATE_UP
+ KEYSTATE_UP
};
-typedef boost::function LLKeyFunc;
+typedef boost::function LLKeyFunc;
typedef std::string (LLKeyStringTranslatorFunc)(const char *label);
enum EKeyboardInsertMode
@@ -50,15 +50,6 @@ enum EKeyboardInsertMode
LL_KIM_OVERWRITE
};
-class LLKeyBinding
-{
-public:
- KEY mKey;
- MASK mMask;
-// const char *mName; // unused
- LLKeyFunc mFunction;
-};
-
class LLWindowCallbacks;
class LLKeyboard
@@ -103,7 +94,8 @@ public:
static BOOL maskFromString(const std::string& str, MASK *mask); // False on failure
static BOOL keyFromString(const std::string& str, KEY *key); // False on failure
- static std::string stringFromKey(KEY key);
+ static std::string stringFromKey(KEY key, bool translate = true);
+ static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"...
static std::string stringFromAccelerator( MASK accel_mask, KEY key );
void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; }
diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp
index d5fa65fe4b..e41ebd42f3 100644
--- a/indra/llwindow/llmousehandler.cpp
+++ b/indra/llwindow/llmousehandler.cpp
@@ -27,7 +27,7 @@
#include "llmousehandler.h"
//virtual
-BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
+BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
{
BOOL handled = FALSE;
if (down)
diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h
index 1dcd0348d8..d221dd117c 100644
--- a/indra/llwindow/llmousehandler.h
+++ b/indra/llwindow/llmousehandler.h
@@ -29,6 +29,7 @@
#include "linden_common.h"
#include "llrect.h"
+#include "indra_constants.h"
// Mostly-abstract interface.
// Intended for use via multiple inheritance.
@@ -46,16 +47,7 @@ public:
SHOW_ALWAYS,
} EShowToolTip;
- typedef enum {
- CLICK_LEFT,
- CLICK_MIDDLE,
- CLICK_RIGHT,
- CLICK_BUTTON4,
- CLICK_BUTTON5,
- CLICK_DOUBLELEFT
- } EClickType;
-
- virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down);
+ virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) = 0;
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) = 0;
virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index e2568e5d5b..c77c14f31e 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -250,7 +250,7 @@ set(viewer_SOURCE_FILES
llblockedlistitem.cpp
llblocklist.cpp
llbox.cpp
- llbreadcrumbview.cpp
+ #llbreadcrumbview.cpp # Unused
llbrowsernotification.cpp
llbuycurrencyhtml.cpp
llcallingcard.cpp
@@ -487,10 +487,11 @@ set(viewer_SOURCE_FILES
llinventoryobserver.cpp
llinventorypanel.cpp
lljoystickbutton.cpp
+ llkeyconflict.cpp
lllandmarkactions.cpp
lllandmarklist.cpp
lllegacyatmospherics.cpp
- lllistbrowser.cpp
+ #lllistbrowser.cpp # Unused
lllistcontextmenu.cpp
lllistview.cpp
lllocalbitmaps.cpp
@@ -652,7 +653,7 @@ set(viewer_SOURCE_FILES
llregioninfomodel.cpp
llregionposition.cpp
llremoteparcelrequest.cpp
- llsavedsettingsglue.cpp
+ #llsavedsettingsglue.cpp # Unused
llsaveoutfitcombobtn.cpp
llscenemonitor.cpp
llsceneview.cpp
@@ -668,6 +669,7 @@ set(viewer_SOURCE_FILES
llsecapi.cpp
llsechandler_basic.cpp
llselectmgr.cpp
+ llsetkeybinddialog.cpp
llsettingspicker.cpp
llsettingsvo.cpp
llshareavatarhandler.cpp
@@ -747,7 +749,7 @@ set(viewer_SOURCE_FILES
llurlhistory.cpp
llurllineeditorctrl.cpp
llurlwhitelist.cpp
- llvectorperfoptions.cpp
+ #llvectorperfoptions.cpp # Unused
llversioninfo.cpp
llviewchildren.cpp
llviewerassetstats.cpp
@@ -774,7 +776,7 @@ set(viewer_SOURCE_FILES
llviewerjointattachment.cpp
llviewerjointmesh.cpp
llviewerjoystick.cpp
- llviewerkeyboard.cpp
+ llviewerinput.cpp
llviewerlayer.cpp
llviewermedia.cpp
llviewermedia_streamingaudio.cpp
@@ -1018,7 +1020,7 @@ set(viewer_HEADER_FILES
llblockedlistitem.h
llblocklist.h
llbox.h
- llbreadcrumbview.h
+ #llbreadcrumbview.h # Unused
llbuycurrencyhtml.h
llcallingcard.h
llcapabilityprovider.h
@@ -1256,10 +1258,11 @@ set(viewer_HEADER_FILES
llinventoryobserver.h
llinventorypanel.h
lljoystickbutton.h
+ llkeyconflict.h
lllandmarkactions.h
lllandmarklist.h
lllightconstants.h
- lllistbrowser.h
+ #lllistbrowser.h # Unused
lllistcontextmenu.h
lllistview.h
lllocalbitmaps.h
@@ -1410,7 +1413,7 @@ set(viewer_HEADER_FILES
llremoteparcelrequest.h
llresourcedata.h
llrootview.h
- llsavedsettingsglue.h
+ #llsavedsettingsglue.h # Unused
llsaveoutfitcombobtn.h
llscenemonitor.h
llsceneview.h
@@ -1427,6 +1430,7 @@ set(viewer_HEADER_FILES
llsecapi.h
llsechandler_basic.h
llselectmgr.h
+ llsetkeybinddialog.h
llsettingspicker.h
llsettingsvo.h
llsidepanelappearance.h
@@ -1509,7 +1513,7 @@ set(viewer_HEADER_FILES
llurlhistory.h
llurllineeditorctrl.h
llurlwhitelist.h
- llvectorperfoptions.h
+ #llvectorperfoptions.h # Unused
llversioninfo.h
llviewchildren.h
llviewerassetstats.h
@@ -1535,7 +1539,7 @@ set(viewer_HEADER_FILES
llviewerjointattachment.h
llviewerjointmesh.h
llviewerjoystick.h
- llviewerkeyboard.h
+ llviewerinput.h
llviewerlayer.h
llviewermedia.h
llviewermediafocus.h
@@ -2061,8 +2065,7 @@ set(viewer_APPSETTINGS_FILES
app_settings/growl_notifications.xml
app_settings/high_graphics.xml
app_settings/ignorable_dialogs.xml
- app_settings/keys.xml
- app_settings/keys_azerty.xml
+ app_settings/key_bindings.xml
app_settings/keywords.ini
app_settings/keywords_lsl_default.xml
app_settings/logcontrol.xml
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index dbe6222fdd..a0b6fce83f 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.4.17
+6.4.18
diff --git a/indra/newview/app_settings/keys.xml b/indra/newview/app_settings/key_bindings.xml
similarity index 64%
rename from indra/newview/app_settings/keys.xml
rename to indra/newview/app_settings/key_bindings.xml
index a8037fec05..18e9b97230 100644
--- a/indra/newview/app_settings/keys.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -28,34 +28,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -64,15 +41,10 @@
-
-
-
-
-
@@ -84,13 +56,8 @@
-
-
-
-
-
@@ -99,20 +66,12 @@
-
-
-
-
-
-
-
-
@@ -139,28 +98,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -179,63 +124,10 @@
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -251,15 +143,11 @@
-
-
-
-
@@ -294,23 +182,23 @@
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
@@ -334,6 +222,8 @@
+
+
@@ -359,5 +249,7 @@
+
+
\ No newline at end of file
diff --git a/indra/newview/app_settings/keys_azerty.xml b/indra/newview/app_settings/keys_azerty.xml
deleted file mode 100644
index d228af0cf4..0000000000
--- a/indra/newview/app_settings/keys_azerty.xml
+++ /dev/null
@@ -1,363 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 4c4cc72d53..f8941bbccc 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -5613,7 +5613,7 @@
DoubleClickAutoPilot
Comment
- Enable double-click auto pilot
+ (Obsolete)Enable double-click auto pilot
Persist
1
Type
@@ -5621,10 +5621,10 @@
Value
0
- DoubleClickTeleport
+ DoubleClickTeleport
Comment
- Enable double-click to teleport where allowed
+ Enable double-click to teleport where allowed (afects minimap and people panel)
Persist
1
Type
@@ -11077,7 +11077,7 @@ Change of this parameter will affect the layout of buttons in notification toast
PushToTalkButton
Comment
- Which button or keyboard key is used for push-to-talk
+ (Obsolete)Which button or keyboard key is used for push-to-talk
Persist
1
Type
@@ -19912,7 +19912,7 @@ Change of this parameter will affect the layout of buttons in notification toast
ClickToWalk
Comment
- Click in world to walk to location
+ (obsolete)Click in world to walk to location
Persist
1
Type
@@ -21148,17 +21148,6 @@ Change of this parameter will affect the layout of buttons in notification toast
Value
1
- FSUseAzertyKeyboardLayout
-
- Comment
- Uses a keyboard layout suitable for keyboards with AZERTY layout.
- Persist
- 1
- Type
- Boolean
- Value
- 0
-
FSNameTagZOffsetCorrection
Comment
@@ -24628,6 +24617,28 @@ Change of this parameter will affect the layout of buttons in notification toast
Value
0
+ FSTelemetryEnableWhenConnected
+
+ Comment
+ Enable telemetry as soon as a server connects
+ Persist
+ 1
+ Type
+ Boolean
+ Value
+ 1
+
+ FSTelemetryActive
+
+ Comment
+ Enable profiling as soon as a server connects. Off by default and non-persistent. Use with FSTelemetryEnableWhenConnected to initiate on startup
+ Persist
+ 0
+ Type
+ Boolean
+ Value
+ 0
+
FSFilterGrowlKeywordDuplicateIMs
Comment
diff --git a/indra/newview/fonts/CascadiaCode-Light.ttf b/indra/newview/fonts/CascadiaCode-Light.ttf
new file mode 100644
index 0000000000..0abd90a372
Binary files /dev/null and b/indra/newview/fonts/CascadiaCode-Light.ttf differ
diff --git a/indra/newview/fonts/CascadiaCodeFONTLOG.txt b/indra/newview/fonts/CascadiaCodeFONTLOG.txt
new file mode 100644
index 0000000000..ed62cf14d2
--- /dev/null
+++ b/indra/newview/fonts/CascadiaCodeFONTLOG.txt
@@ -0,0 +1,80 @@
+FONTLOG for Cascadia Code
+===================================
+
+This file provides detailed information on the Cascadia Code font. This information should be distributed along with the Cascadia Code font and any derivative works.
+
+Basic Font Information
+-----------------------------------
+
+Cascadia Code is a monospaced font shipped by Microsoft. It includes programming ligatures and is intended for use in terminal applications as well as text editors.
+
+Contribution Information
+-----------------------------------
+
+Documentation and contribution guidelines can be found at: https://github.com/microsoft/cascadia-code
+
+ChangeLog
+-----------------------------------
+
+09-25-2019 (Aaron Bell) Bug Fixes and Improvements
+
+09-18-2019 (Aaron Bell) Cascadia Code Version 1909.16
+- Initial release
+
+10-04-2019 (Aaron Bell) Cascadia Code Version 1910.04
+- Addition of Latin-1 characters
+- Addition of box drawing glyphs
+11-20-2019 (Aaron Bell) Cascadia Code Version 1911.20
+- Cyrillic, Greek, Vietnamese, and many other symbols added
+- Font converted to UFO with a build workflow
+- font rehinted
+- many other fixes!
+
+04-29-2020 (Aaron Bell) April bug fixes
+- Many small bug fixes from the last few months
+
+05-05-2020 Font vertical metrics locked
+
+05-15-2020 (Aaron Bell, Dustin Howett) [Version 2005.15]
+Fixed WinDescent value to improve line spacing
+
+06-29-2020 (Aaron Bell) Variable font conversion
+Converted Cascadia Code to a Variable font with a weight axis
+
+
+06-29-2020 (Aaron Bell) [Version 2007.01]
+Reworked Cascadia Code to be a variable font with 6 named variations ranging
+from ExtraLight to Bold.
+Split the long equals ligature (==) for earier reading
+Removed the hexadeciaml 'x' alternate
+Corrected malformed IJacute dioacritics
+Introduced a compatibility layout for PowerLine glyphs that will
+be used in GDI
+
+08-25-2020 (Aaron Bell) [Version 2008.25]
+Started generating static TTFs and hinting them with ttfautohint
+Aligned the powerline glyphs to the font metrics exactly
+Realigned the box drawing glyphs to match the letters
+Added anchors to all alphabetic characters (and brevecomb-cy)
+added fi/fl ligatures (decomposed!)
+Fixed the weight of horncomb in bold
+
+9-14-2020
+1) Added support for Salishan language groups
+2) Remastered mark positioning for glyphs with 2 diacritics (needed for Salishan)
+3) Rebuild Build Script to simplify code
+4) Fixed minor other hinting issues
+5) Fixed RVRN substitutions for heavy weight
+
+9-21-2020
+1) Correcting mark positioning for salishan
+
+Acknowledgements
+-----------------------------------
+
+If you make modifications, be sure to add your name (N), email (E), web-address (if you have one) (W), and description (D). This list is in alphabetical order.
+
+N: Aaron Bell
+E: aaron@sajatypeworks.com
+W: http://sajatypeworks.com
+D: Original font designer
diff --git a/indra/newview/fonts/CascadiaCodeLICENSE.txt b/indra/newview/fonts/CascadiaCodeLICENSE.txt
new file mode 100644
index 0000000000..40f856f6ec
--- /dev/null
+++ b/indra/newview/fonts/CascadiaCodeLICENSE.txt
@@ -0,0 +1,94 @@
+Copyright (c) 2019 - Present, Microsoft Corporation,
+with Reserved Font Name Cascadia Code.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/indra/newview/fonts/fonts.xml b/indra/newview/fonts/fonts.xml
index 00ce0e8b17..4d921b7a5d 100644
--- a/indra/newview/fonts/fonts.xml
+++ b/indra/newview/fonts/fonts.xml
@@ -32,6 +32,9 @@
STIXGeneral.otf
Thonburi.ttc
+
+ DejaVuSans.ttf
+
ocra.ttf
+
+ CascadiaCode-Light.ttf
+
+
DejaVuSans.ttf
@@ -172,6 +180,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="8.0"
/>
+
+
+
+
+ CascadiaCode-Light.ttf
+
+ meiryo.TTC
+ YuGothR.ttc
+ MSGOTHIC.TTC
+ gulim.ttc
+ simhei.ttf
+ ArialUni.ttf
+ msyh.ttc
+ seguisym.ttf
+ nirmala.ttf
+ tahoma.ttf
+ Cambria.ttc
+ micross.ttf
+ malgun.ttf
+
+
+ ヒラギノ角ゴシック W3.ttc
+ ヒラギノ角ゴ Pro W3.otf
+ ヒラギノ角ゴ ProN W3.otf
+ ヒラギノ明朝 ProN W3.ttc
+ AppleGothic.dfont
+ AppleGothic.ttf
+ AppleSDGothicNeo-Regular.otf
+ AppleSDGothicNeo.ttc
+ 华文细黑.ttf
+ PingFang.ttc
+ STIXGeneral.otf
+ Thonburi.ttc
+
+
+ DejaVuSans.ttf
+
+
+
+
+ CascadiaCode-Light.ttf
+
+ arialbd.ttf
+
+
+ Helvetica.dfont
+
+
+
+
+ CascadiaCode-Light.ttf
+
+ arial.ttf
+
+
+ Helvetica.dfont
+
+
+
+
+ CascadiaCode-Light.ttf
+
+
+
+ CascadiaCode-Light.ttf
+
+
+
+ CascadiaCode-Light.ttf
+
+
+
+ CascadiaCode-Light.ttf
+
+
+
+ SourceCodePro-Regular.ttf
+
+
+
+ ocra.ttf
+
+
+
+ CascadiaCode-Light.ttf
+
+
+
+ CascadiaCode-Light.ttf
+
+
+
+ CascadiaCode-Light.ttf
+
+
+
+ CascadiaCode-Light.ttf
+
+
+
+ CascadiaCode-Light.ttf
+
+
+
+ CascadiaCode-Light.ttf
+
+ arial.ttf
+
+
+ arial.ttf
+
+
+
+
+ CascadiaCode-Light.ttf
+
+ arialbd.ttf
+
+
+ arialbd.ttf
+
+
+
+
+ CascadiaCode-Light.ttf
+
+ ariali.ttf
+
+
+ ariali.ttf
+
+
+
+
+ CascadiaCode-Light.ttf
+
+ arialbi.ttf
+
+
+ arialbi.ttf
+
+
+
+
+ times.ttf
+ CascadiaCode-Light.ttf
+
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/newview/fonts/fonts_celestia_medium_redux.xml b/indra/newview/fonts/fonts_celestia_medium_redux.xml
index d177a69a56..eb4c726e36 100644
--- a/indra/newview/fonts/fonts_celestia_medium_redux.xml
+++ b/indra/newview/fonts/fonts_celestia_medium_redux.xml
@@ -32,6 +32,9 @@
STIXGeneral.otf
Thonburi.ttc
+
+ DejaVuSans.ttf
+
ocra.ttf
+
+ CascadiaCode-Light.ttf
+
+
DejaVuSans.ttf
@@ -172,6 +180,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="8.0"
/>
+
PingFang.ttc
STIXGeneral.otf
+
+ DejaVuSans.ttf
+
ocra.ttf
+
+ CascadiaCode-Light.ttf
+
+
DejaVuSansAllCaps.ttf
@@ -170,6 +178,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="8.0"
/>
+
STIXGeneral.otf
Thonburi.ttc
+
+ DejaVuSans.ttf
+
ocra.ttf
-
+
+
+ CascadiaCode-Light.ttf
+
+
DroidSans.ttf
@@ -172,6 +180,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="8.0"
/>
+
STIXGeneral.otf
Thonburi.ttc
+
+ DejaVuSans.ttf
+
ocra.ttf
+
+ CascadiaCode-Light.ttf
+
+
opendyslexic.ttf
@@ -172,6 +180,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="8.0"
/>
+
STIXGeneral.otf
Thonburi.ttc
+
+ DejaVuSans.ttf
+
ocra.ttf
+
+ CascadiaCode-Light.ttf
+
+
DejaVuSans.ttf
@@ -172,6 +180,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="9.0"
/>
+
STIXGeneral.otf
Thonburi.ttc
+
+ DejaVuSans.ttf
+
ocra.ttf
+
+ CascadiaCode-Light.ttf
+
+
MobiSans.ttf
@@ -172,6 +180,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="8.0"
/>
+
STIXGeneral.otf
Thonburi.ttc
+
+ DejaVuSans.ttf
+
ocra.ttf
+
+ CascadiaCode-Light.ttf
+
+
NotoSansCombined-Regular.ttf
@@ -172,6 +180,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="8.0"
/>
+
STIXGeneral.otf
Thonburi.ttc
+
+ DejaVuSans.ttf
+
ocra.ttf
+
+ CascadiaCode-Light.ttf
+
+
Roboto-Regular.ttf
@@ -172,6 +180,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="8.0"
/>
+
STIXGeneral.otf
Thonburi.ttc
+
+ DejaVuSans.ttf
+
ocra.ttf
+
+ CascadiaCode-Light.ttf
+
+
DejaVuSans.ttf
@@ -176,6 +184,10 @@
comment="Size for monospaced font (points, or 1/72 of an inch)"
size="8.0"
/>
+
Load Firestorm's registration page from within the viewer itself
+ // LLWeb::loadURLExternal(LLTrans::getString("create_account_url"));
+ LLWeb::loadURLInternal(LLTrans::getString("create_account_url"));
+ //
}
}
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 3be82ce9be..14e09d4773 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -408,7 +408,7 @@ CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
WriteINIStr "$SMPROGRAMS\$INSTSHORTCUT\SL Create Account.url" \
"InternetShortcut" "URL" \
- "https://join.secondlife.com/"
+ "https://www.firestormviewer.org/join-secondlife/"
WriteINIStr "$SMPROGRAMS\$INSTSHORTCUT\SL Your Account.url" \
"InternetShortcut" "URL" \
"https://www.secondlife.com/account/"
diff --git a/indra/newview/lggcontactsets.cpp b/indra/newview/lggcontactsets.cpp
index 8ad4cce2df..4a1c76113f 100644
--- a/indra/newview/lggcontactsets.cpp
+++ b/indra/newview/lggcontactsets.cpp
@@ -1048,6 +1048,13 @@ LGGContactSets::ContactSet* LGGContactSets::getContactSet(const std::string& set
return NULL;
}
+bool LGGContactSets::checkCustomName(const LLUUID& id, bool& dn_removed, std::string& pseudonym)
+{
+ dn_removed = hasDisplayNameRemoved(id);
+ pseudonym = getPseudonym(id);
+ return hasPseudonym(id);
+}
+
// static
bool LGGContactSets::handleAddContactSetCallback(const LLSD& notification, const LLSD& response)
{
diff --git a/indra/newview/lggcontactsets.h b/indra/newview/lggcontactsets.h
index fa326210e7..76d87cdc7a 100644
--- a/indra/newview/lggcontactsets.h
+++ b/indra/newview/lggcontactsets.h
@@ -72,6 +72,8 @@ public:
bool hasDisplayNameRemoved(const LLUUID& friend_id);
bool hasDisplayNameRemoved(uuid_vec_t ids);
+ bool checkCustomName(const LLUUID& id, bool& dn_removed, std::string& pseudonym);
+
string_vec_t getFriendSets(const LLUUID& friend_id);
string_vec_t getAllContactSets();
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 23e6d443e1..b8a7bb482b 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -3011,10 +3011,19 @@ void LLAgentCamera::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate, BOOL re
LLVector3 at_axis;
if (!isAgentAvatarValid() || !gAgentAvatarp->getParent())
{
- at_axis = LLViewerCamera::getInstance()->getAtAxis();
- at_axis.mV[VZ] = 0.f;
- at_axis.normalize();
- gAgent.resetAxes(at_axis);
+ // In case of front view rotate agent to look into direction opposite to camera
+ // In case of rear view rotate agent into diraction same as camera, e t c
+ LLVector3 vect = getCameraOffsetInitial();
+ F32 rotxy = F32(atan2(vect.mV[VY], vect.mV[VX]));
+
+ LLCoordFrame frameCamera = *((LLCoordFrame*)LLViewerCamera::getInstance());
+ // front view angle rotxy is zero, rear view rotxy angle is 180, compensate
+ frameCamera.yaw((180 * DEG_TO_RAD) - rotxy);
+ at_axis = frameCamera.getAtAxis();
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ gAgent.resetAxes(at_axis);
+ gAgent.yaw(0);
}
}
}
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 6b3699de30..5611f6adfb 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -3456,7 +3456,7 @@ void LLAppearanceMgr::updateIsDirty()
{
LLViewerInventoryItem *item = *i;
- if (item->getName() == FSLSLBridge::instance().currentFullName())
+ if (FSLSLBridge::instance().isBridgeValid() && item && item->getLinkedUUID() == FSLSLBridge::instance().getBridge()->getUUID())
{
cof_items.erase( i );
break;
@@ -3688,6 +3688,19 @@ void update_base_outfit_after_ordering()
}
}
+ // Exclude LSL bridge or the following size check will always fail!
+ for (LLInventoryModel::item_array_t::iterator i = cof_item_array.begin(); i != cof_item_array.end(); ++i)
+ {
+ LLViewerInventoryItem *item = *i;
+
+ if (FSLSLBridge::instance().isBridgeValid() && item && item->getLinkedUUID() == FSLSLBridge::instance().getBridge()->getUUID())
+ {
+ cof_item_array.erase(i);
+ break;
+ }
+ }
+ //
+
if (outfit_item_array.size() != cof_item_array.size())
{
return;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 7fdcdfaad3..7817bf9210 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -49,6 +49,7 @@
#include "llwindow.h"
#include "llviewerstats.h"
#include "llviewerstatsrecorder.h"
+#include "llkeyconflict.h" // for legacy keybinding support, remove later
#include "llmarketplacefunctions.h"
#include "llmarketplacenotifications.h"
#include "llmd5.h"
@@ -164,7 +165,7 @@
#include "llapr.h"
#include
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
#include "lllfsthread.h"
#include "llworkerthread.h"
#include "lltexturecache.h"
@@ -282,6 +283,8 @@
#include "fsradar.h"
#include "fsassetblacklist.h"
+#include "fstelemetry.h" // Tracy profiler support
+
#if (LL_LINUX || LL_SOLARIS) && LL_GTK
#include "glib.h"
#endif // (LL_LINUX || LL_SOLARIS) && LL_GTK
@@ -1194,31 +1197,6 @@ bool LLAppViewer::init()
gGLManager.getGLInfo(gDebugInfo);
gGLManager.printGLInfoString();
- // Load Default bindings
- // Optional AZERTY keyboard layout
- //std::string key_bindings_file = gDirUtilp->findFile("keys.xml",
- std::string keyBindingFileName("keys.xml");
- if (gSavedSettings.getBOOL("FSUseAzertyKeyboardLayout"))
- {
- keyBindingFileName = "keys_azerty.xml";
- }
- std::string key_bindings_file = gDirUtilp->findFile(keyBindingFileName,
- //
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-
-
- if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
- {
- std::string key_bindings_file = gDirUtilp->findFile("keys.ini",
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- if (!gViewerKeyboard.loadBindings(key_bindings_file))
- {
- LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
- }
- }
-
// If we don't have the right GL requirements, exit.
if (!gGLManager.mHasRequirements)
{
@@ -1517,6 +1495,9 @@ bool LLAppViewer::init()
//onChangeFrameLimit(gSavedSettings.getLLSD("FramePerSecondLimit"));
//
+ // Load User's bindings
+ loadKeyBindings();
+
return true;
}
@@ -1652,7 +1633,28 @@ bool LLAppViewer::doFrame()
{
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
LLSD newFrame;
-
+// telemetry enabling.
+// This ifdef is optional but better to avoid even low overhead code in main loop where not needed.
+#ifdef FS_HAS_TELEMETRY_SUPPORT
+ static bool one_time{false};
+ static LLCachedControl profiling_enabled_when_connected(gSavedSettings, "FSTelemetryEnableWhenConnected");
+ if( !one_time && (gFrameCount % 10 == 0) )
+ {
+ if(!FSTelemetry::active && profiling_enabled_when_connected && FSTelemetryIsConnected)
+ {
+ FSTelemetry::active = true;
+ gSavedSettings.setBOOL("FSTelemetryActive", TRUE); // keep the setting in sync.
+ one_time=true; // prevent reset race if we disable manually.
+ LL_INFOS() << "Profiler or collector connected" << LL_ENDL;
+ }
+ else if(!profiling_enabled_when_connected)
+ {
+ // no point in checking if we are not waiting.
+ one_time = true;
+ }
+ }
+#endif
+//
// MaxFPS Viewer-Chui merge error
LLTimer periodicRenderingTimer;
BOOL restore_rendering_masks = FALSE;
@@ -1755,6 +1757,7 @@ bool LLAppViewer::doFrame()
{
joystick->scanJoystick();
gKeyboard->scanKeyboard();
+ gViewerInput.scanMouse();
// Chalice Yao's crouch toggle
static LLCachedControl fsCrouchToggle(gSavedPerAccountSettings, "FSCrouchToggle");
static LLCachedControl fsCrouchToggleStatus(gSavedPerAccountSettings, "FSCrouchToggleStatus");
@@ -1953,7 +1956,7 @@ bool LLAppViewer::doFrame()
LL_INFOS() << "Exiting main_loop" << LL_ENDL;
}
-
+ FSFrameMark; // Tracy support delineate Frame
return ! LLApp::isRunning();
}
@@ -5088,6 +5091,134 @@ void LLAppViewer::addOnIdleCallback(const boost::function& cb)
LLDeferredTaskList::instance().addTask(cb);
}
+void LLAppViewer::loadKeyBindings()
+{
+ std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml");
+#if 1
+ // Legacy support
+ // Remove #if-#endif section half a year after DRTVWR-501 releases.
+ // Mouse actions are part of keybinding file since DRTVWR-501 instead of being stored in
+ // settings.xml. To support legacy viewers that were storing in settings.xml we need to
+ // transfer old variables to new format.
+ // Also part of backward compatibility is present in LLKeyConflictHandler to modify
+ // legacy variables on changes in new system (to make sure we won't enforce
+ // legacy values again if user dropped to defaults in new system)
+ if (LLVersionInfo::getInstance()->getChannelAndVersion() != gLastRunVersion
+ || !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet
+ {
+ // copy mouse actions and voice key changes to new file
+ LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL;
+ // Load settings from file
+ LLKeyConflictHandler third_person_view(LLKeyConflictHandler::MODE_THIRD_PERSON);
+ LLKeyConflictHandler sitting_view(LLKeyConflictHandler::MODE_SITTING);
+
+ // Since we are only modifying keybindings if personal file doesn't exist yet,
+ // it should be safe to just overwrite the value
+ // If key is already in use somewhere by default, LLKeyConflictHandler should resolve it.
+ BOOL value = gSavedSettings.getBOOL("DoubleClickAutoPilot");
+ third_person_view.registerControl("walk_to",
+ 0,
+ value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE,
+ KEY_NONE,
+ MASK_NONE,
+ value);
+
+ U32 index = value ? 1 : 0; // we can store multiple combinations per action, so if first is in use by doubleclick, go to second
+ value = gSavedSettings.getBOOL("ClickToWalk");
+ third_person_view.registerControl("walk_to",
+ index,
+ value ? EMouseClickType::CLICK_LEFT : EMouseClickType::CLICK_NONE,
+ KEY_NONE,
+ MASK_NONE,
+ value);
+
+ value = gSavedSettings.getBOOL("DoubleClickTeleport");
+ third_person_view.registerControl("teleport_to",
+ 0,
+ value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE,
+ KEY_NONE,
+ MASK_NONE,
+ value);
+
+ // sitting also supports teleport
+ sitting_view.registerControl("teleport_to",
+ 0,
+ value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE,
+ KEY_NONE,
+ MASK_NONE,
+ value);
+
+ std::string key_string = gSavedSettings.getString("PushToTalkButton");
+ EMouseClickType mouse = EMouseClickType::CLICK_NONE;
+ KEY key = KEY_NONE;
+ if (key_string == "MiddleMouse")
+ {
+ mouse = EMouseClickType::CLICK_MIDDLE;
+ }
+ else if (key_string == "MouseButton4")
+ {
+ mouse = EMouseClickType::CLICK_BUTTON4;
+ }
+ else if (key_string == "MouseButton5")
+ {
+ mouse = EMouseClickType::CLICK_BUTTON5;
+ }
+ else
+ {
+ LLKeyboard::keyFromString(key_string, &key);
+ }
+
+ value = gSavedSettings.getBOOL("PushToTalkToggle");
+ std::string control_name = value ? "toggle_voice" : "voice_follow_key";
+ third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
+ sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
+
+ if (third_person_view.hasUnsavedChanges())
+ {
+ // calls loadBindingsXML()
+ third_person_view.saveToSettings();
+ }
+
+ if (sitting_view.hasUnsavedChanges())
+ {
+ // calls loadBindingsXML()
+ sitting_view.saveToSettings();
+ }
+
+ // in case of voice we need to repeat this in other modes
+
+ for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+ {
+ // edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment
+ if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING)
+ {
+ LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i);
+
+ handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
+
+ if (handler.hasUnsavedChanges())
+ {
+ // calls loadBindingsXML()
+ handler.saveToSettings();
+ }
+ }
+ }
+ }
+ // since something might have gone wrong or there might have been nothing to save
+ // (and because otherwise following code will have to be encased in else{}),
+ // load everything one last time
+#endif
+ if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))
+ {
+ // Failed to load custom bindings, try default ones
+ key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml");
+ if (!gViewerInput.loadBindingsXML(key_bindings_file))
+ {
+ LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL;
+ }
+ }
+}
+
void LLAppViewer::purgeCache()
{
LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL;
@@ -6174,6 +6305,7 @@ void LLAppViewer::disconnectViewer()
gInventory.getLibraryOwnerID());
}
+ LLAvatarNameCache::instance().setCustomNameCheckCallback(LLAvatarNameCache::custom_name_check_callback_t()); // Contact sets
saveNameCache();
if (LLExperienceCache::instanceExists())
{
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 7c16cad534..c2e19b9103 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -208,6 +208,8 @@ public:
void purgeCache(); // Clear the local cache.
void purgeCacheImmediate(); //clear local cache immediately.
S32 updateTextureThreads(F32 max_time);
+
+ void loadKeyBindings();
// mute/unmute the system's master audio
virtual void setMasterSystemAudioMute(bool mute);
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index 0bac4cff3f..20b62a063a 100644
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -43,7 +43,7 @@
#include "llmimetypes.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
-#include "llsavedsettingsglue.h"
+// #include "llsavedsettingsglue.h" # Unused
#include "llviewertexturelist.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index d8e45acac7..757fefbf86 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -250,6 +250,21 @@ void activate_camera_tool()
/*static*/ bool LLFloaterCamera::inFreeCameraMode()
{
LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance();
+
+ // Phototools camera
+ if (!floater_camera)
+ {
+ floater_camera = LLFloaterCamera::findPhototoolsInstance();
+ }
+ //
+
+ // Optional small camera floater
+ if (!floater_camera)
+ {
+ floater_camera = LLFloaterCamera::findSmallInstance();
+ }
+ //
+
if (floater_camera && floater_camera->mCurrMode == CAMERA_CTRL_MODE_FREE_CAMERA && gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
{
return true;
diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp
index 3d5af0149e..48913cc91e 100644
--- a/indra/newview/llfloaterjoystick.cpp
+++ b/indra/newview/llfloaterjoystick.cpp
@@ -52,6 +52,11 @@
#include
#endif
+// FIRE-14344 - show joystick buttons
+const std::string JOYSTICK_BUTTON_ON ( "\xE2\xAC\xA4" ); // U+2B24 BLACK LARGE CIRCLE
+const std::string JOYSTICK_BUTTON_OFF( "\xE2\x97\xAF" ); // U+25EF WHITE LARGE CIRCLE
+//
+
static LLTrace::SampleStatHandle<> sJoystickAxis0("Joystick axis 0"),
sJoystickAxis1("Joystick axis 1"),
sJoystickAxis2("Joystick axis 2"),
@@ -68,7 +73,6 @@ static LLTrace::SampleStatHandle<>* sJoystickAxes[6] =
&sJoystickAxis5
};
-
#if LL_WINDOWS && !LL_MESA_HEADLESS
BOOL CALLBACK di8_list_devices_callback(LPCDIDEVICEINSTANCE device_instance_ptr, LPVOID pvRef)
@@ -113,10 +117,20 @@ void LLFloaterJoystick::draw()
refreshListOfDevices();
}
+ // FIRE-14344 - If we are on the login screen, this value will be 0.0f and we know we
+ // have to update the joystick status by ourselves
+ if (gFrameIntervalSeconds.value() == 0.0f)
+ {
+ joystick->updateStatus();
+ }
+ //
+
for (U32 i = 0; i < 6; i++)
{
F32 value = joystick->getJoystickAxis(i);
- sample(*sJoystickAxes[i], value * gFrameIntervalSeconds.value());
+ // FIRE-14344 - using the frame interval seems to break the graphs
+ // sample(*sJoystickAxes[i], value * gFrameIntervalSeconds.value());
+ sample(*sJoystickAxes[i], value);
if (mAxisStatsBar[i])
{
F32 minbar, maxbar;
@@ -129,6 +143,23 @@ void LLFloaterJoystick::draw()
}
}
+ // FIRE-14344 - show joystick buttons
+ std::string buttons;
+ for (U32 i = 0; i < 16; i++)
+ {
+ U32 value = joystick->getJoystickButton(i);
+ if (value == 0)
+ {
+ buttons += JOYSTICK_BUTTON_OFF;
+ }
+ else
+ {
+ buttons += JOYSTICK_BUTTON_ON;
+ }
+ }
+ mJoystickButtons->setText(buttons);
+ //
+
LLFloater::draw();
}
@@ -137,7 +168,10 @@ BOOL LLFloaterJoystick::postBuild()
center();
// Micro Save on calls to gSavedSettings
//F32 range = gSavedSettings.getBOOL("Cursor3D") ? 128.f : 2.f;
- F32 range = m3DCursor ? 128.f : 2.f;
+ // FIRE-14344 - use 1.f for the graph ranges instead of 128.f : 2.f to get better resolution -
+ // needs testing with an actual absolute pointer device if the range scales in a useful way when
+ // not starting at 128.f
+ F32 range = 1.f;
for (U32 i = 0; i < 6; i++)
{
@@ -160,6 +194,9 @@ BOOL LLFloaterJoystick::postBuild()
childSetAction("cancel_btn", onClickCancel, this);
childSetAction("ok_btn", onClickOK, this);
+ // FIRE-14344 - show joystick buttons
+ mJoystickButtons = getChild("joystick_buttons");
+
refresh();
refreshListOfDevices();
return TRUE;
@@ -294,7 +331,9 @@ void LLFloaterJoystick::refreshListOfDevices()
std::string desc = LLViewerJoystick::getInstance()->getDescription();
if (!desc.empty())
{
- LLSD value = LLSD::Integer(0);
+ // FIRE-30846 - Select the first detected device, don't fall back to 0 which will select "None"
+ // LLSD value = LLSD::Integer(0);
+ LLSD value = LLSD::Integer(1);
addDevice(desc, value);
mHasDeviceList = true;
}
diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h
index 1d46efd3f6..5bda3a0b1e 100644
--- a/indra/newview/llfloaterjoystick.h
+++ b/indra/newview/llfloaterjoystick.h
@@ -97,6 +97,9 @@ private:
// stats view
LLStatBar* mAxisStatsBar[6];
+
+ // FIRE-14344 - show joystick buttons
+ LLTextBase* mJoystickButtons;
};
#endif
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 97c7e4fde6..379b0f3eeb 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -81,8 +81,9 @@
#include "lltrans.h"
#include "llviewercontrol.h"
#include "llviewercamera.h"
-#include "llviewerwindow.h"
+#include "llviewereventrecorder.h"
#include "llviewermessage.h"
+#include "llviewerwindow.h"
#include "llviewershadermgr.h"
#include "llviewerthrottle.h"
#include "llvoavatarself.h"
@@ -166,15 +167,18 @@
#endif
//
+// FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+#include "llfiltereditor.h"
+
// FIRE-6340, FIRE-6567 - Setting Bandwidth issues
//const F32 BANDWIDTH_UPDATER_TIMEOUT = 0.5f;
char const* const VISIBILITY_DEFAULT = "default";
char const* const VISIBILITY_HIDDEN = "hidden";
//control value for middle mouse as talk2push button
-const static std::string MIDDLE_MOUSE_CV = "MiddleMouse"; // for voice client and redability
-const static std::string MOUSE_BUTTON_4_CV = "MouseButton4";
-const static std::string MOUSE_BUTTON_5_CV = "MouseButton5";
+//const static std::string MIDDLE_MOUSE_CV = "MiddleMouse"; // for voice client and redability
+//const static std::string MOUSE_BUTTON_4_CV = "MouseButton4";
+//const static std::string MOUSE_BUTTON_5_CV = "MouseButton5";
/// This must equal the maximum value set for the IndirectMaxComplexity slider in panel_preferences_graphics1.xml
static const U32 INDIRECT_MAX_ARC_OFF = 101; // all the way to the right == disabled
@@ -188,6 +192,13 @@ static const F32 MIN_ARC_LOG = log(MIN_ARC_LIMIT);
static const F32 MAX_ARC_LOG = log(MAX_ARC_LIMIT);
static const F32 ARC_LIMIT_MAP_SCALE = (MAX_ARC_LOG - MIN_ARC_LOG) / (MAX_INDIRECT_ARC_LIMIT - MIN_INDIRECT_ARC_LIMIT);
+// FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+// define these constants so any future changes will be easier and less error prone
+static const S32 COLUMN_POPUP_SPACER = 0;
+static const S32 COLUMN_POPUP_CHECKBOX = 1;
+static const S32 COLUMN_POPUP_LABEL = 2;
+//
+
struct LabelDef : public LLInitParam::Block
{
Mandatory name;
@@ -207,87 +218,6 @@ struct LabelTable : public LLInitParam::Block
{}
};
-class LLVoiceSetKeyDialog : public LLModalDialog
-{
-public:
- LLVoiceSetKeyDialog(const LLSD& key);
- ~LLVoiceSetKeyDialog();
-
- /*virtual*/ BOOL postBuild();
-
- void setParent(LLFloaterPreference* parent) { mParent = parent; }
-
- BOOL handleKeyHere(KEY key, MASK mask);
- BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down);
- static void onCancel(void* user_data);
-
-private:
- LLFloaterPreference* mParent;
-};
-
-LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key)
- : LLModalDialog(key),
- mParent(NULL)
-{
-}
-
-//virtual
-BOOL LLVoiceSetKeyDialog::postBuild()
-{
- childSetAction("Cancel", onCancel, this);
- getChild("Cancel")->setFocus(TRUE);
-
- gFocusMgr.setKeystrokesOnly(TRUE);
-
- return TRUE;
-}
-
-LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog()
-{
-}
-
-BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask)
-{
- BOOL result = TRUE;
-
- if (key == 'Q' && mask == MASK_CONTROL)
- {
- result = FALSE;
- }
- else if (mParent)
- {
- mParent->setKey(key);
- }
- closeFloater();
- return result;
-}
-
-BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
-{
- BOOL result = FALSE;
- if (down
- && (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5)
- && mask == 0)
- {
- mParent->setMouse(clicktype);
- result = TRUE;
- closeFloater();
- }
- else
- {
- result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
- }
-
- return result;
-}
-
-//static
-void LLVoiceSetKeyDialog::onCancel(void* user_data)
-{
- LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data;
- self->closeFloater();
-}
-
// global functions
@@ -474,37 +404,6 @@ bool callback_pick_debug_search(const LLSD& notification, const LLSD& response)
}
//
-/*bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option && floater )
- {
- if ( floater )
- {
- floater->setAllIgnored();
- // LLFirstUse::disableFirstUse();
- floater->buildPopupLists();
- }
- }
- return false;
-}
-
-bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if ( 0 == option && floater )
- {
- if ( floater )
- {
- floater->resetAllIgnored();
- //LLFirstUse::resetFirstUse();
- floater->buildPopupLists();
- }
- }
- return false;
-}
-*/
-
void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator)
{
numerator = 0;
@@ -529,8 +428,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mGotPersonalInfo(false),
mOriginalIMViaEmail(false),
mLanguageChanged(false),
- mAvatarDataInitialized(false),
- mClickActionDirty(false)
+ mAvatarDataInitialized(false)
{
LLConversationLog::instance().addObserver(this);
@@ -539,7 +437,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
static bool registered_dialog = false;
if (!registered_dialog)
{
- LLFloaterReg::add("voice_set_key", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
+ LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build);
registered_dialog = true;
}
@@ -558,13 +456,14 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this));
// mCommitCallbackRegistrar.add("Pref.ClickSkin", boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2));
// mCommitCallbackRegistrar.add("Pref.SelectSkin", boost::bind(&LLFloaterPreference::onSelectSkin, this));
- mCommitCallbackRegistrar.add("Pref.VoiceSetKey", boost::bind(&LLFloaterPreference::onClickSetKey, this));
- mCommitCallbackRegistrar.add("Pref.VoiceSetClearKey", boost::bind(&LLFloaterPreference::onClickClearKey, this)); // FIRE-3803: Clear voice toggle button
- mCommitCallbackRegistrar.add("Pref.VoiceSetMiddleMouse", boost::bind(&LLFloaterPreference::onClickSetMiddleMouse, this));
// Handled centrally now
// mCommitCallbackRegistrar.add("Pref.SetSounds", boost::bind(&LLFloaterPreference::onClickSetSounds, this));
- mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this));
- mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this));
+ // FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+ // mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this));
+ // mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this));
+ mCommitCallbackRegistrar.add("Pref.SelectPopup", boost::bind(&LLFloaterPreference::onSelectPopup, this));
+ mCommitCallbackRegistrar.add("Pref.UpdatePopupFilter", boost::bind(&LLFloaterPreference::onUpdatePopupFilter, this));
+ //
mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this));
mCommitCallbackRegistrar.add("Pref.RenderExceptions", boost::bind(&LLFloaterPreference::onClickRenderExceptions, this));
mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this));
@@ -889,6 +788,12 @@ BOOL LLFloaterPreference::postBuild()
#endif
//
+ // FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+ mPopupList = getChild("all_popups");
+ mPopupList->setFilterColumn(COLUMN_POPUP_LABEL);
+ mPopupFilter = getChild("popup_filter");
+ //
+
return TRUE;
}
@@ -984,25 +889,18 @@ LLFloaterPreference::~LLFloaterPreference()
LLConversationLog::instance().removeObserver(this);
}
-void LLFloaterPreference::draw()
-{
- // Performance improvement
- //BOOL has_first_selected = (getChildRef("disabled_popups").getFirstSelected()!=NULL);
- //gSavedSettings.setBOOL("FirstSelectedDisabledPopups", has_first_selected);
- //
- //has_first_selected = (getChildRef("enabled_popups").getFirstSelected()!=NULL);
- //gSavedSettings.setBOOL("FirstSelectedEnabledPopups", has_first_selected);
-
- static LLScrollListCtrl* disabled_popups = getChild("disabled_popups");
- static LLScrollListCtrl* enabled_popups = getChild("enabled_popups");
- BOOL has_first_selected = disabled_popups->getFirstSelected() != NULL;
- gSavedSettings.setBOOL("FirstSelectedDisabledPopups", has_first_selected);
- has_first_selected = enabled_popups->getFirstSelected() != NULL;
- gSavedSettings.setBOOL("FirstSelectedEnabledPopups", has_first_selected);
- //
-
- LLFloater::draw();
-}
+// FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+// void LLFloaterPreference::draw()
+// {
+// BOOL has_first_selected = (getChildRef("disabled_popups").getFirstSelected()!=NULL);
+// gSavedSettings.setBOOL("FirstSelectedDisabledPopups", has_first_selected);
+//
+// has_first_selected = (getChildRef("enabled_popups").getFirstSelected()!=NULL);
+// gSavedSettings.setBOOL("FirstSelectedEnabledPopups", has_first_selected);
+//
+// LLFloater::draw();
+//}
+//
void LLFloaterPreference::saveSettings()
{
@@ -1087,12 +985,6 @@ void LLFloaterPreference::apply()
saveAvatarProperties();
- if (mClickActionDirty)
- {
- updateClickActionSettings();
- mClickActionDirty = false;
- }
-
// Fix resetting graphics preset on cancel; Save preset here because cancel() gets called in either way!
saveGraphicsPreset(gSavedSettings.getString("PresetGraphicActive"));
}
@@ -1127,11 +1019,7 @@ void LLFloaterPreference::cancel()
// reverts any changes to current skin
//gSavedSettings.setString("SkinCurrent", sSkin);
- if (mClickActionDirty)
- {
- updateClickActionControls();
- mClickActionDirty = false;
- }
+ updateClickActionViews();
LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance("prefs_proxy");
if (advanced_proxy_settings)
@@ -1242,15 +1130,21 @@ void LLFloaterPreference::onOpen(const LLSD& key)
onChangeAnimationFolder();
// Load (double-)click to walk/teleport settings.
- updateClickActionControls();
+ updateClickActionViews();
// Load UI Sounds tabs settings.
updateUISoundsControls();
// Enabled/disabled popups, might have been changed by user actions
// while preferences floater was closed.
- buildPopupLists();
+ // FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+ // buildPopupLists();
+ mPopupFilter->setText(LLStringExplicit(""));
+ mPopupList->setFilterString(LLStringExplicit(""));
+
+ buildPopupList();
+ //
//get the options that were checked
// [CHUI MERGE]
@@ -2046,16 +1940,79 @@ void LLFloaterPreference::refreshSkin(void* data)
self->getChild("skin_selection", true)->setValue(sSkin);
}
*/
-void LLFloaterPreference::buildPopupLists()
+
+// FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+// void LLFloaterPreference::buildPopupLists()
+// {
+// LLScrollListCtrl& disabled_popups =
+// getChildRef("disabled_popups");
+// LLScrollListCtrl& enabled_popups =
+// getChildRef("enabled_popups");
+//
+// disabled_popups.deleteAllItems();
+// enabled_popups.deleteAllItems();
+//
+// for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin();
+// iter != LLNotifications::instance().templatesEnd();
+// ++iter)
+// {
+// LLNotificationTemplatePtr templatep = iter->second;
+// LLNotificationFormPtr formp = templatep->mForm;
+//
+// LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType();
+// if (ignore <= LLNotificationForm::IGNORE_NO)
+// continue;
+//
+// LLSD row;
+// row["columns"][0]["value"] = formp->getIgnoreMessage();
+// row["columns"][0]["font"] = "SANSSERIF_SMALL";
+// row["columns"][0]["width"] = 400;
+//
+// LLScrollListItem* item = NULL;
+//
+// bool show_popup = !formp->getIgnored();
+// if (!show_popup)
+// {
+// if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
+// {
+// // Default responses are declared in "ignores" settings group, see llnotifications.cpp
+// //LLSD last_response = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("Default" + templatep->mName);
+// LLSD last_response = LLUI::getInstance()->mSettingGroups["ignores"]->getLLSD("Default" + templatep->mName);
+// //
+// if (!last_response.isUndefined())
+// {
+// for (LLSD::map_const_iterator it = last_response.beginMap();
+// it != last_response.endMap();
+// ++it)
+// {
+// if (it->second.asBoolean())
+// {
+// row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString();
+// row["columns"][1]["font"] = "SANSSERIF_SMALL";
+// row["columns"][1]["width"] = 360;
+// break;
+// }
+// }
+// }
+// }
+// item = disabled_popups.addElement(row);
+// }
+// else
+// {
+// item = enabled_popups.addElement(row);
+// }
+//
+// if (item)
+// {
+// item->setUserdata((void*)&iter->first);
+// }
+// }
+// }
+
+void LLFloaterPreference::buildPopupList()
{
- LLScrollListCtrl& disabled_popups =
- getChildRef("disabled_popups");
- LLScrollListCtrl& enabled_popups =
- getChildRef("enabled_popups");
-
- disabled_popups.deleteAllItems();
- enabled_popups.deleteAllItems();
-
+ mPopupList->deleteAllItems();
+
for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin();
iter != LLNotifications::instance().templatesEnd();
++iter)
@@ -2066,63 +2023,44 @@ void LLFloaterPreference::buildPopupLists()
LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType();
if (ignore <= LLNotificationForm::IGNORE_NO)
continue;
-
- LLSD row;
- row["columns"][0]["value"] = formp->getIgnoreMessage();
- row["columns"][0]["font"] = "SANSSERIF_SMALL";
- row["columns"][0]["width"] = 400;
-
- LLScrollListItem* item = NULL;
-
+
bool show_popup = !formp->getIgnored();
- if (!show_popup)
- {
-// Don't show chosen option for ignored dialogs in the list. There is only one
-// notification that makes use of it ("ReplaceAttachment") and it would make the
-// list appear truncated.
-#if 0
- if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
- {
- // Default responses are declared in "ignores" settings group, see llnotifications.cpp
- //LLSD last_response = LLUI::getInstance()->mSettingGroups["config"]->getLLSD("Default" + templatep->mName);
- LLSD last_response = LLUI::getInstance()->mSettingGroups["ignores"]->getLLSD("Default" + templatep->mName);
- //
- if (!last_response.isUndefined())
- {
- for (LLSD::map_const_iterator it = last_response.beginMap();
- it != last_response.endMap();
- ++it)
- {
- if (it->second.asBoolean())
- {
- row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString();
- row["columns"][1]["font"] = "SANSSERIF_SMALL";
- row["columns"][1]["width"] = 360;
- break;
- }
- }
- }
- }
-#endif
- item = disabled_popups.addElement(row);
- }
- else
- {
- item = enabled_popups.addElement(row);
- }
-
+
+ LLSD row;
+
+ // column COLUMN_POPUP_SPACER makes things look good, since "halign" and "center" or LLFontGL::HCENTER don't work -Zi
+ row["columns"][COLUMN_POPUP_CHECKBOX]["type"] = "checkbox";
+ row["columns"][COLUMN_POPUP_CHECKBOX]["column"] = "alert_enabled_check";
+ row["columns"][COLUMN_POPUP_CHECKBOX]["value"] = show_popup;
+ row["columns"][COLUMN_POPUP_LABEL]["column"] = "alert_label";
+ row["columns"][COLUMN_POPUP_LABEL]["value"] = formp->getIgnoreMessage();
+
+ LLScrollListItem* item = mPopupList->addElement(row);
+
if (item)
{
item->setUserdata((void*)&iter->first);
}
}
-
- // Let's sort it so we can find stuff!
- enabled_popups.sortByColumnIndex(0, TRUE);
- disabled_popups.sortByColumnIndex(0, TRUE);
- //
}
+void LLFloaterPreference::onSelectPopup()
+{
+ LLScrollListItem* last = mPopupList->getLastSelectedItem();
+ for (auto popup : mPopupList->getAllSelected())
+ {
+ LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)(popup->getUserdata()));
+ std::string notification_name = templatep->mName;
+ LLUI::getInstance()->mSettingGroups["ignores"]->setBOOL(notification_name, last->getColumn(COLUMN_POPUP_CHECKBOX)->getValue().asBoolean());
+ }
+}
+
+void LLFloaterPreference::onUpdatePopupFilter()
+{
+ mPopupList->setFilterString(mPopupFilter->getValue().asString());
+}
+//
+
void LLFloaterPreference::refreshEnabledState()
{
// Improved graphics preferences
@@ -2744,6 +2682,7 @@ void LLFloaterPreference::refresh()
{
advanced->refresh();
}
+ updateClickActionViews();
}
void LLFloaterPreferenceGraphicsAdvanced::refresh()
@@ -2785,79 +2724,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data)
refresh();
}
-void LLFloaterPreference::onClickSetKey()
-{
- LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance("voice_set_key", LLSD(), TRUE);
- if (dialog)
- {
- dialog->setParent(this);
- }
-}
-
-// FIRE-3803: Clear voice toggle button
-void LLFloaterPreference::onClickClearKey()
-{
- gSavedSettings.setString("PushToTalkButton", "");
-}
-//
-
-void LLFloaterPreference::setKey(KEY key)
-{
- getChild("modifier_combo")->setValue(LLKeyboard::stringFromKey(key));
- // update the control right away since we no longer wait for apply
- getChild("modifier_combo")->onCommit();
-}
-
-void LLFloaterPreference::setMouse(LLMouseHandler::EClickType click)
-{
- std::string bt_name;
- std::string ctrl_value;
- switch (click)
- {
- case LLMouseHandler::CLICK_MIDDLE:
- bt_name = "middle_mouse";
- ctrl_value = MIDDLE_MOUSE_CV;
- break;
- case LLMouseHandler::CLICK_BUTTON4:
- bt_name = "button4_mouse";
- ctrl_value = MOUSE_BUTTON_4_CV;
- break;
- case LLMouseHandler::CLICK_BUTTON5:
- bt_name = "button5_mouse";
- ctrl_value = MOUSE_BUTTON_5_CV;
- break;
- default:
- break;
- }
-
- if (!ctrl_value.empty())
- {
- LLUICtrl* p2t_line_editor = getChild("modifier_combo");
- // We are using text control names for readability and compatibility with voice
- p2t_line_editor->setControlValue(ctrl_value);
- // Fix crash "Failed to find string middle_mouse in panel Media Voice tab loaded from file"
- //LLPanel* advanced_preferences = dynamic_cast(p2t_line_editor->getParent());
- LLPanel* advanced_preferences = dynamic_cast(p2t_line_editor->getParent()->getParent()->getParent());
- //
- if (advanced_preferences)
- {
- p2t_line_editor->setValue(advanced_preferences->getString(bt_name));
- }
- }
-}
-
-void LLFloaterPreference::onClickSetMiddleMouse()
-{
- LLUICtrl* p2t_line_editor = getChild("modifier_combo");
-
- // update the control right away since we no longer wait for apply
- p2t_line_editor->setControlValue(MIDDLE_MOUSE_CV);
-
- //push2talk button "middle mouse" control value is in English, need to localize it for presentation
- LLPanel* audioPanel=getChild("audio");
- p2t_line_editor->setValue(audioPanel->getString("middle_mouse"));
-}
-
// Handled centrally now
/*
void LLFloaterPreference::onClickSetSounds()
@@ -2877,49 +2743,39 @@ void LLFloaterPreference::onClickPreviewUISound(const LLSD& ui_sound_id)
}
// FIRE-8190: Preview function for "UI Sounds" Panel
-/*
-void LLFloaterPreference::onClickSkipDialogs()
-{
- LLNotificationsUtil::add("SkipShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_skip_dialogs, _1, _2, this));
-}
+// FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+// void LLFloaterPreference::onClickEnablePopup()
+// {
+// LLScrollListCtrl& disabled_popups = getChildRef("disabled_popups");
+//
+// std::vector items = disabled_popups.getAllSelected();
+// std::vector::iterator itor;
+// for (itor = items.begin(); itor != items.end(); ++itor)
+// {
+// LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata()));
+// //gSavedSettings.setWarning(templatep->mName, TRUE);
+// std::string notification_name = templatep->mName;
+// LLUI::getInstance()->mSettingGroups["ignores"]->setBOOL(notification_name, TRUE);
+// }
+//
+// buildPopupLists();
+// }
-void LLFloaterPreference::onClickResetDialogs()
-{
- LLNotificationsUtil::add("ResetShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_reset_dialogs, _1, _2, this));
-}
- */
-
-void LLFloaterPreference::onClickEnablePopup()
-{
- LLScrollListCtrl& disabled_popups = getChildRef("disabled_popups");
-
- std::vector items = disabled_popups.getAllSelected();
- std::vector::iterator itor;
- for (itor = items.begin(); itor != items.end(); ++itor)
- {
- LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata()));
- //gSavedSettings.setWarning(templatep->mName, TRUE);
- std::string notification_name = templatep->mName;
- LLUI::getInstance()->mSettingGroups["ignores"]->setBOOL(notification_name, TRUE);
- }
-
- buildPopupLists();
-}
-
-void LLFloaterPreference::onClickDisablePopup()
-{
- LLScrollListCtrl& enabled_popups = getChildRef("enabled_popups");
-
- std::vector items = enabled_popups.getAllSelected();
- std::vector::iterator itor;
- for (itor = items.begin(); itor != items.end(); ++itor)
- {
- LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata()));
- templatep->mForm->setIgnored(true);
- }
-
- buildPopupLists();
-}
+// void LLFloaterPreference::onClickDisablePopup()
+// {
+// LLScrollListCtrl& enabled_popups = getChildRef("enabled_popups");
+//
+// std::vector items = enabled_popups.getAllSelected();
+// std::vector::iterator itor;
+// for (itor = items.begin(); itor != items.end(); ++itor)
+// {
+// LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate(*(std::string*)((*itor)->getUserdata()));
+// templatep->mForm->setIgnored(true);
+// }
+//
+// buildPopupLists();
+// }
+//
void LLFloaterPreference::resetAllIgnored()
{
@@ -3517,7 +3373,7 @@ void LLFloaterPreference::onClickAdvanced()
void LLFloaterPreference::onClickActionChange()
{
- mClickActionDirty = true;
+ updateClickActionControls();
}
void LLFloaterPreference::onClickPermsDefault()
@@ -3557,26 +3413,6 @@ void LLFloaterPreference::onLogChatHistorySaved()
}
}
-void LLFloaterPreference::updateClickActionSettings()
-{
- const int single_clk_action = getChild("single_click_action_combo")->getValue().asInteger();
- const int double_clk_action = getChild("double_click_action_combo")->getValue().asInteger();
-
- gSavedSettings.setBOOL("ClickToWalk", single_clk_action == 1);
- gSavedSettings.setBOOL("DoubleClickAutoPilot", double_clk_action == 1);
- gSavedSettings.setBOOL("DoubleClickTeleport", double_clk_action == 2);
-}
-
-void LLFloaterPreference::updateClickActionControls()
-{
- const bool click_to_walk = gSavedSettings.getBOOL("ClickToWalk");
- const bool dbl_click_to_walk = gSavedSettings.getBOOL("DoubleClickAutoPilot");
- const bool dbl_click_to_teleport = gSavedSettings.getBOOL("DoubleClickTeleport");
-
- getChild("single_click_action_combo")->setValue((int)click_to_walk);
- getChild("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk);
-}
-
// Load UI Sounds tabs settings
void LLFloaterPreference::updateUISoundsControls()
{
@@ -3600,6 +3436,86 @@ void LLFloaterPreference::updateUISoundsControls()
}
//
+void LLFloaterPreference::updateClickActionControls()
+{
+ const int single_clk_action = getChild("single_click_action_combo")->getValue().asInteger();
+ const int double_clk_action = getChild("double_click_action_combo")->getValue().asInteger();
+
+ // Todo: This is a very ugly way to get access to keybindings.
+ // Reconsider possible options.
+ // Potential option: make constructor of LLKeyConflictHandler private
+ // but add a getter that will return shared pointer for specific
+ // mode, pointer should only exist so long as there are external users.
+ // In such case we won't need to do this 'dynamic_cast' nightmare.
+ // updateTable() can also be avoided
+ LLTabContainer* tabcontainer = getChild("pref core");
+ for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
+ iter != tabcontainer->getChildList()->end(); ++iter)
+ {
+ LLView* view = *iter;
+ LLPanelPreferenceControls* panel = dynamic_cast(view);
+ if (panel)
+ {
+ panel->setKeyBind("walk_to",
+ EMouseClickType::CLICK_LEFT,
+ KEY_NONE,
+ MASK_NONE,
+ single_clk_action == 1);
+
+ panel->setKeyBind("walk_to",
+ EMouseClickType::CLICK_DOUBLELEFT,
+ KEY_NONE,
+ MASK_NONE,
+ double_clk_action == 1);
+
+ panel->setKeyBind("teleport_to",
+ EMouseClickType::CLICK_DOUBLELEFT,
+ KEY_NONE,
+ MASK_NONE,
+ double_clk_action == 2);
+
+ panel->updateAndApply();
+ }
+ }
+}
+
+void LLFloaterPreference::updateClickActionViews()
+{
+ bool click_to_walk = false;
+ bool dbl_click_to_walk = false;
+ bool dbl_click_to_teleport = false;
+
+ // Todo: This is a very ugly way to get access to keybindings.
+ // Reconsider possible options.
+ LLTabContainer* tabcontainer = getChild("pref core");
+ for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
+ iter != tabcontainer->getChildList()->end(); ++iter)
+ {
+ LLView* view = *iter;
+ LLPanelPreferenceControls* panel = dynamic_cast(view);
+ if (panel)
+ {
+ click_to_walk = panel->canKeyBindHandle("walk_to",
+ EMouseClickType::CLICK_LEFT,
+ KEY_NONE,
+ MASK_NONE);
+
+ dbl_click_to_walk = panel->canKeyBindHandle("walk_to",
+ EMouseClickType::CLICK_DOUBLELEFT,
+ KEY_NONE,
+ MASK_NONE);
+
+ dbl_click_to_teleport = panel->canKeyBindHandle("teleport_to",
+ EMouseClickType::CLICK_DOUBLELEFT,
+ KEY_NONE,
+ MASK_NONE);
+ }
+ }
+
+ getChild("single_click_action_combo")->setValue((int)click_to_walk);
+ getChild("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk);
+}
+
void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param)
{
LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue()));
@@ -3865,24 +3781,6 @@ BOOL LLPanelPreference::postBuild()
getChild("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized));
}
- //////////////////////PanelAdvanced ///////////////////
- if (hasChild("modifier_combo", TRUE))
- {
- //localizing if push2talk button is set to middle mouse
- std::string modifier_value = getChild("modifier_combo")->getValue().asString();
- if (MIDDLE_MOUSE_CV == modifier_value)
- {
- getChild("modifier_combo")->setValue(getString("middle_mouse"));
- }
- else if (MOUSE_BUTTON_4_CV == modifier_value)
- {
- getChild("modifier_combo")->setValue(getString("button4_mouse"));
- }
- else if (MOUSE_BUTTON_5_CV == modifier_value)
- {
- getChild("modifier_combo")->setValue(getString("button5_mouse"));
- }
- }
// Panel Setup (Network) -WoLf
if (hasChild("connection_port_enabled"))
{
@@ -4528,6 +4426,585 @@ void LLPanelPreferenceGraphics::setHardwareDefaults()
LLPanelPreference::setHardwareDefaults();
}
+//------------------------LLPanelPreferenceControls--------------------------------
+static LLPanelInjector t_pref_contrls("panel_preference_controls");
+
+LLPanelPreferenceControls::LLPanelPreferenceControls()
+ :LLPanelPreference(),
+ mEditingColumn(-1),
+ mEditingMode(0)
+{
+ // MODE_COUNT - 1 because there are currently no settings assigned to 'saved settings'.
+ for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+ {
+ mConflictHandler[i].setLoadMode((LLKeyConflictHandler::ESourceMode)i);
+ }
+}
+
+LLPanelPreferenceControls::~LLPanelPreferenceControls()
+{
+}
+
+BOOL LLPanelPreferenceControls::postBuild()
+{
+ // populate list of controls
+ pControlsTable = getChild("controls_list");
+ pKeyModeBox = getChild("key_mode");
+
+ pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this));
+ pKeyModeBox->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onModeCommit, this));
+ getChild("restore_defaults")->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsBtn, this));
+
+ return TRUE;
+}
+
+void LLPanelPreferenceControls::regenerateControls()
+{
+ mEditingMode = pKeyModeBox->getValue().asInteger();
+ mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode);
+ populateControlTable();
+}
+
+bool LLPanelPreferenceControls::addControlTableColumns(const std::string &filename)
+{
+ LLXMLNodePtr xmlNode;
+ LLScrollListCtrl::Contents contents;
+ if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
+ {
+ LL_WARNS() << "Failed to load " << filename << LL_ENDL;
+ return false;
+ }
+ LLXUIParser parser;
+ parser.readXUI(xmlNode, contents, filename);
+
+ if (!contents.validateBlock())
+ {
+ return false;
+ }
+
+ for (LLInitParam::ParamIterator::const_iterator col_it = contents.columns.begin();
+ col_it != contents.columns.end();
+ ++col_it)
+ {
+ pControlsTable->addColumn(*col_it);
+ }
+
+ return true;
+}
+
+bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
+{
+ LLXMLNodePtr xmlNode;
+ LLScrollListCtrl::Contents contents;
+ if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
+ {
+ LL_WARNS() << "Failed to load " << filename << LL_ENDL;
+ return false;
+ }
+ LLXUIParser parser;
+ parser.readXUI(xmlNode, contents, filename);
+
+ if (!contents.validateBlock())
+ {
+ return false;
+ }
+
+ LLScrollListCell::Params cell_params;
+ // init basic cell params
+ cell_params.font = LLFontGL::getFontSansSerif();
+ cell_params.font_halign = LLFontGL::LEFT;
+ cell_params.column = "";
+ cell_params.value = "";
+
+
+ for (LLInitParam::ParamIterator::const_iterator row_it = contents.rows.begin();
+ row_it != contents.rows.end();
+ ++row_it)
+ {
+ std::string control = row_it->value.getValue().asString();
+ if (!control.empty() && control != "menu_separator")
+ {
+ bool show = true;
+ bool enabled = mConflictHandler[mEditingMode].canAssignControl(control);
+ if (!enabled)
+ {
+ // If empty: this is a placeholder to make sure user won't assign
+ // value by accident, don't show it
+ // If not empty: predefined control combination user should see
+ // to know that combination is reserved
+ show = !mConflictHandler[mEditingMode].isControlEmpty(control);
+ // example: teleport_to and walk_to in first person view, and
+ // sitting related functions, see generatePlaceholders()
+ }
+
+ if (show)
+ {
+ // At the moment viewer is hardcoded to assume that columns are named as lst_ctrl%d
+ LLScrollListItem::Params item_params(*row_it);
+ item_params.enabled.setValue(enabled);
+
+ S32 num_columns = pControlsTable->getNumColumns();
+ for (S32 col = 1; col < num_columns; col++)
+ {
+ cell_params.column = llformat("lst_ctrl%d", col);
+ cell_params.value = mConflictHandler[mEditingMode].getControlString(control, col - 1);
+ item_params.columns.add(cell_params);
+ }
+ pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM);
+ }
+ }
+ else
+ {
+ // Separator example:
+ //
+ //
+ //
+ pControlsTable->addRow(*row_it, EAddPosition::ADD_BOTTOM);
+ }
+ }
+ return true;
+}
+
+void LLPanelPreferenceControls::addControlTableSeparator()
+{
+ LLScrollListItem::Params separator_params;
+ separator_params.enabled(false);
+ LLScrollListCell::Params column_params;
+ column_params.type = "icon";
+ column_params.value = "menu_separator";
+ column_params.column = "lst_action";
+ column_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f);
+ column_params.font_halign = LLFontGL::HCENTER;
+ separator_params.columns.add(column_params);
+ pControlsTable->addRow(separator_params, EAddPosition::ADD_BOTTOM);
+}
+
+void LLPanelPreferenceControls::populateControlTable()
+{
+ pControlsTable->clearRows();
+ pControlsTable->clearColumns();
+
+ // Add columns
+ std::string filename;
+ switch ((LLKeyConflictHandler::ESourceMode)mEditingMode)
+ {
+ case LLKeyConflictHandler::MODE_THIRD_PERSON:
+ case LLKeyConflictHandler::MODE_FIRST_PERSON:
+ case LLKeyConflictHandler::MODE_EDIT_AVATAR:
+ case LLKeyConflictHandler::MODE_SITTING:
+ filename = "control_table_contents_columns_basic.xml";
+ break;
+ default:
+ // Either unknown mode or MODE_SAVED_SETTINGS
+ // It doesn't have UI or actual settings yet
+ LL_INFOS() << "Unimplemented mode" << LL_ENDL;
+ return;
+ }
+ addControlTableColumns(filename);
+
+ // Add rows.
+ // Each file represents individual visual group (movement/camera/media...)
+ if (mEditingMode == LLKeyConflictHandler::MODE_FIRST_PERSON)
+ {
+ // Don't display whole camera and editing groups
+ addControlTableRows("control_table_contents_movement.xml");
+ addControlTableSeparator();
+ addControlTableRows("control_table_contents_media.xml");
+ }
+ // MODE_THIRD_PERSON; MODE_EDIT_AVATAR; MODE_SITTING
+ else if (mEditingMode < LLKeyConflictHandler::MODE_SAVED_SETTINGS)
+ {
+ // In case of 'sitting' mode, movements still apply due to vehicles
+ // but walk_to is not supported and will be hidden by addControlTableRows
+ addControlTableRows("control_table_contents_movement.xml");
+ addControlTableSeparator();
+
+ addControlTableRows("control_table_contents_camera.xml");
+ addControlTableSeparator();
+
+ addControlTableRows("control_table_contents_editing.xml");
+ addControlTableSeparator();
+
+ addControlTableRows("control_table_contents_media.xml");
+ }
+ else
+ {
+ LL_INFOS() << "Unimplemented mode" << LL_ENDL;
+ return;
+ }
+}
+
+void LLPanelPreferenceControls::updateTable()
+{
+ mEditingControl.clear();
+ std::vector list = pControlsTable->getAllData();
+ for (S32 i = 0; i < list.size(); ++i)
+ {
+ std::string control = list[i]->getValue();
+ if (!control.empty())
+ {
+ LLScrollListCell* cell = NULL;
+
+ S32 num_columns = pControlsTable->getNumColumns();
+ for (S32 col = 1; col < num_columns; col++)
+ {
+ cell = list[i]->getColumn(col);
+ cell->setValue(mConflictHandler[mEditingMode].getControlString(control, col - 1));
+ }
+ }
+ }
+ pControlsTable->deselectAllItems();
+}
+
+void LLPanelPreferenceControls::apply()
+{
+ for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+ {
+ if (mConflictHandler[i].hasUnsavedChanges())
+ {
+ mConflictHandler[i].saveToSettings();
+ }
+ }
+}
+
+void LLPanelPreferenceControls::cancel()
+{
+ for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+ {
+ if (mConflictHandler[i].hasUnsavedChanges())
+ {
+ mConflictHandler[i].clear();
+ }
+ }
+ pControlsTable->clearRows();
+ pControlsTable->clearColumns();
+}
+
+void LLPanelPreferenceControls::saveSettings()
+{
+ for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+ {
+ if (mConflictHandler[i].hasUnsavedChanges())
+ {
+ mConflictHandler[i].saveToSettings();
+ mConflictHandler[i].clear();
+ }
+ }
+
+ S32 mode = pKeyModeBox->getValue().asInteger();
+ if (mConflictHandler[mode].empty() || pControlsTable->isEmpty())
+ {
+ regenerateControls();
+ }
+}
+
+void LLPanelPreferenceControls::resetDirtyChilds()
+{
+ regenerateControls();
+}
+
+void LLPanelPreferenceControls::onListCommit()
+{
+ LLScrollListItem* item = pControlsTable->getFirstSelected();
+ if (item == NULL)
+ {
+ return;
+ }
+
+ std::string control = item->getValue();
+
+ if (control.empty())
+ {
+ pControlsTable->deselectAllItems();
+ return;
+ }
+
+ if (!mConflictHandler[mEditingMode].canAssignControl(control))
+ {
+ pControlsTable->deselectAllItems();
+ return;
+ }
+
+ S32 cell_ind = item->getSelectedCell();
+ if (cell_ind <= 0)
+ {
+ pControlsTable->deselectAllItems();
+ return;
+ }
+
+ // List does not tell us what cell was clicked, so we have to figure it out manually, but
+ // fresh mouse coordinates are not yet accessible during onCommit() and there are other issues,
+ // so we cheat: remember item user clicked at, trigger 'key dialog' on hover that comes next,
+ // use coordinates from hover to calculate cell
+
+ LLScrollListCell* cell = item->getColumn(cell_ind);
+ if (cell)
+ {
+ LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance("keybind_dialog", LLSD());
+ if (dialog)
+ {
+ mEditingControl = control;
+ mEditingColumn = cell_ind;
+ dialog->setParent(this, pControlsTable, DEFAULT_KEY_FILTER);
+
+ LLFloater* root_floater = gFloaterView->getParentFloater(this);
+ if (root_floater)
+ root_floater->addDependentFloater(dialog);
+ dialog->openFloater();
+ dialog->setFocus(TRUE);
+ }
+ }
+ else
+ {
+ pControlsTable->deselectAllItems();
+ }
+}
+
+void LLPanelPreferenceControls::onModeCommit()
+{
+ mEditingMode = pKeyModeBox->getValue().asInteger();
+ if (mConflictHandler[mEditingMode].empty())
+ {
+ // opening for first time
+ mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode);
+ }
+ populateControlTable();
+}
+
+void LLPanelPreferenceControls::onRestoreDefaultsBtn()
+{
+ LLNotificationsUtil::add("PreferenceControlsDefaults", LLSD(), LLSD(), boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsResponse, this, _1, _2));
+}
+
+void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ switch(option)
+ {
+ case 0: // All
+ for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+ {
+ mConflictHandler[i].resetToDefaults();
+ // Apply changes to viewer as 'temporary'
+ mConflictHandler[i].saveToSettings(true);
+
+ // notify comboboxes in move&view about potential change
+ LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences");
+ if (instance)
+ {
+ instance->updateClickActionViews();
+ }
+ }
+
+ updateTable();
+ break;
+ case 1: // Current
+ mConflictHandler[mEditingMode].resetToDefaults();
+ // Apply changes to viewer as 'temporary'
+ mConflictHandler[mEditingMode].saveToSettings(true);
+
+ if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON)
+ {
+ // notify comboboxes in move&view about potential change
+ LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences");
+ if (instance)
+ {
+ instance->updateClickActionViews();
+ }
+ }
+
+ updateTable();
+ break;
+ case 2: // Cancel
+ default:
+ //exit;
+ break;
+ }
+}
+
+// Bypass to let Move & view read values without need to create own key binding handler
+// Assumes third person view
+// Might be better idea to just move whole mConflictHandler into LLFloaterPreference
+bool LLPanelPreferenceControls::canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask)
+{
+ S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
+ if (mConflictHandler[mode].empty())
+ {
+ // opening for first time
+ mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON);
+ }
+
+ return mConflictHandler[mode].canHandleControl(control, click, key, mask);
+}
+
+// Bypass to let Move & view modify values without need to create own key binding handler
+// Assumes third person view
+// Might be better idea to just move whole mConflictHandler into LLFloaterPreference
+void LLPanelPreferenceControls::setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set)
+{
+ S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
+ if (mConflictHandler[mode].empty())
+ {
+ // opening for first time
+ mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON);
+ }
+
+ if (!mConflictHandler[mode].canAssignControl(mEditingControl))
+ {
+ return;
+ }
+
+ bool already_recorded = mConflictHandler[mode].canHandleControl(control, click, key, mask);
+ if (set)
+ {
+ if (already_recorded)
+ {
+ // nothing to do
+ return;
+ }
+
+ // find free spot to add data, if no free spot, assign to first
+ S32 index = 0;
+ for (S32 i = 0; i < 3; i++)
+ {
+ if (mConflictHandler[mode].getControl(control, i).isEmpty())
+ {
+ index = i;
+ break;
+ }
+ }
+ mConflictHandler[mode].registerControl(control, index, click, key, mask, true);
+ }
+ else if (!set)
+ {
+ if (!already_recorded)
+ {
+ // nothing to do
+ return;
+ }
+
+ // find specific control and reset it
+ for (S32 i = 0; i < 3; i++)
+ {
+ LLKeyData data = mConflictHandler[mode].getControl(control, i);
+ if (data.mMouse == click && data.mKey == key && data.mMask == mask)
+ {
+ mConflictHandler[mode].clearControl(control, i);
+ }
+ }
+ }
+}
+
+void LLPanelPreferenceControls::updateAndApply()
+{
+ S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
+ mConflictHandler[mode].saveToSettings(true);
+ updateTable();
+}
+
+// from LLSetKeybindDialog's interface
+bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes)
+{
+ if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
+ {
+ return true;
+ }
+
+ if ( mEditingColumn > 0)
+ {
+ if (all_modes)
+ {
+ for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+ {
+ if (mConflictHandler[i].empty())
+ {
+ mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i);
+ }
+ mConflictHandler[i].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true);
+ // Apply changes to viewer as 'temporary'
+ mConflictHandler[i].saveToSettings(true);
+ }
+ }
+ else
+ {
+ mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true);
+ // Apply changes to viewer as 'temporary'
+ mConflictHandler[mEditingMode].saveToSettings(true);
+ }
+ }
+
+ updateTable();
+
+ if ((mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes)
+ && (mEditingControl == "walk_to"
+ || mEditingControl == "teleport_to"
+ || click == CLICK_LEFT
+ || click == CLICK_DOUBLELEFT))
+ {
+ // notify comboboxes in move&view about potential change
+ LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences");
+ if (instance)
+ {
+ instance->updateClickActionViews();
+ }
+ }
+
+ return true;
+}
+
+void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes)
+{
+ if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
+ {
+ return;
+ }
+
+ if (mEditingColumn > 0)
+ {
+ if (all_modes)
+ {
+ for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+ {
+ if (mConflictHandler[i].empty())
+ {
+ mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i);
+ }
+ mConflictHandler[i].resetToDefault(mEditingControl, mEditingColumn - 1);
+ // Apply changes to viewer as 'temporary'
+ mConflictHandler[i].saveToSettings(true);
+ }
+ }
+ else
+ {
+ mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1);
+ // Apply changes to viewer as 'temporary'
+ mConflictHandler[mEditingMode].saveToSettings(true);
+ }
+ }
+ updateTable();
+
+ if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes)
+ {
+ // notify comboboxes in move&view about potential change
+ LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences");
+ if (instance)
+ {
+ instance->updateClickActionViews();
+ }
+ }
+}
+
+void LLPanelPreferenceControls::onCancelKeyBind()
+{
+ pControlsTable->deselectAllItems();
+}
+
LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key)
: LLFloater(key)
{
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 2a3b075167..2f0bec02e7 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -37,6 +37,8 @@
#include "llavatarpropertiesprocessor.h"
#include "llconversationlog.h"
#include "llsearcheditor.h"
+#include "llsetkeybinddialog.h"
+#include "llkeyconflict.h"
#include "llaudioengine.h" // Output device selection
@@ -45,13 +47,18 @@ class LLPanelPreference;
class LLPanelLCD;
class LLPanelDebug;
class LLMessageSystem;
+class LLComboBox;
class LLScrollListCtrl;
+class LLScrollListCell;
class LLSliderCtrl;
class LLSD;
class LLTextBox;
class LLComboBox;
class LLLineEditor;
+// FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+class LLFilterEditor;
+
namespace ll
{
namespace prefs
@@ -80,7 +87,9 @@ public:
void apply();
void cancel();
- /*virtual*/ void draw();
+ // FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+ // /*virtual*/ void draw();
+ //
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ void onClose(bool app_quitting);
@@ -108,6 +117,8 @@ public:
void selectPrivacyPanel();
void selectChatPanel();
void getControlNames(std::vector& names);
+ // updates click/double-click action controls depending on values from settings.xml
+ void updateClickActionViews();
// Make onBtnOk() public for settings backup panel
//protected:
@@ -146,10 +157,9 @@ protected:
// callback for commit in the "Single click on land" and "Double click on land" comboboxes.
void onClickActionChange();
- // updates click/double-click action settings depending on controls values
- void updateClickActionSettings();
- // updates click/double-click action controls depending on values from settings.xml
+ // updates click/double-click action keybindngs depending on view values
void updateClickActionControls();
+
// updates UI Sounds controls depending on values from settings.xml
void updateUISoundsControls();
@@ -166,7 +176,6 @@ protected:
// Group Notices and chiclets location setting conversion BOOL => S32
void onShowGroupNoticesTopRightChanged();
-
// Dynamic texture memory calculation
void handleDynamicTextureMemoryChanged();
@@ -198,11 +207,6 @@ public:
void onClickBrowseSettingsDir();
void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata);
void onSelectSkin();
- void onClickSetKey();
- void onClickClearKey(); // FIRE-3803: Clear voice toggle button
- void setKey(KEY key);
- void setMouse(LLMouseHandler::EClickType click);
- void onClickSetMiddleMouse();
// void onClickSetSounds(); // Handled centrally now
void onClickPreviewUISound(const LLSD& ui_sound_id); // FIRE-8190: Preview function for "UI Sounds" Panel
void setPreprocInclude();
@@ -211,8 +215,12 @@ public:
void setExternalEditor();
void changeExternalEditorPath(const std::vector& filenames);
//
- void onClickEnablePopup();
- void onClickDisablePopup();
+ // FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+ // void onClickEnablePopup();
+ // void onClickDisablePopup();
+ void onSelectPopup();
+ void onUpdatePopupFilter();
+ //
void resetAllIgnored();
void setAllIgnored();
void onClickLogPath();
@@ -271,7 +279,12 @@ public:
void applyUIColor(LLUICtrl* ctrl, const LLSD& param);
void getUIColor(LLUICtrl* ctrl, const LLSD& param);
void onLogChatHistorySaved();
- void buildPopupLists();
+
+ // FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+ // void buildPopupLists();
+ void buildPopupList();
+ //
+
static void refreshSkin(void* data);
void selectPanel(const LLSD& name);
// Build fix
@@ -289,7 +302,6 @@ private:
static std::string sSkin;
notifications_map mNotificationOptions;
- bool mClickActionDirty; ///< Set to true when the click/double-click options get changed by user.
bool mGotPersonalInfo;
bool mOriginalIMViaEmail;
bool mLanguageChanged;
@@ -308,6 +320,11 @@ private:
void onUpdateFilterTerm( bool force = false );
void collectSearchableItems();
+
+ // FIRE-19539 - Include the alert messages in Prefs>Notifications>Alerts in preference Search.
+ LLScrollListCtrl* mPopupList;
+ LLFilterEditor* mPopupFilter;
+ //
};
class LLPanelPreference : public LLPanel
@@ -399,6 +416,60 @@ private:
LOG_CLASS(LLPanelPreferenceGraphics);
};
+class LLPanelPreferenceControls : public LLPanelPreference, public LLKeyBindResponderInterface
+{
+ LOG_CLASS(LLPanelPreferenceControls);
+public:
+ LLPanelPreferenceControls();
+ virtual ~LLPanelPreferenceControls();
+
+ BOOL postBuild();
+
+ void apply();
+ void cancel();
+ void saveSettings();
+ void resetDirtyChilds();
+
+ void onListCommit();
+ void onModeCommit();
+ void onRestoreDefaultsBtn();
+ void onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response);
+
+ // Bypass to let Move & view read values without need to create own key binding handler
+ // Todo: consider a better way to share access to keybindings
+ bool canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask);
+ // Bypasses to let Move & view modify values without need to create own key binding handler
+ void setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set /*set or reset*/ );
+ void updateAndApply();
+
+ // from interface
+ /*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
+ /*virtual*/ void onDefaultKeyBind(bool all_modes);
+ /*virtual*/ void onCancelKeyBind();
+
+private:
+ // reloads settings, discards current changes, updates table
+ void regenerateControls();
+
+ // These fuctions do not clean previous content
+ bool addControlTableColumns(const std::string &filename);
+ bool addControlTableRows(const std::string &filename);
+ void addControlTableSeparator();
+
+ // Cleans content and then adds content from xml files according to current mEditingMode
+ void populateControlTable();
+
+ // Updates keybindings from storage to table
+ void updateTable();
+
+ LLScrollListCtrl* pControlsTable;
+ LLComboBox *pKeyModeBox;
+ LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT];
+ std::string mEditingControl;
+ S32 mEditingColumn;
+ S32 mEditingMode;
+};
+
class LLFloaterPreferenceGraphicsAdvanced : public LLFloater
{
public:
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
new file mode 100644
index 0000000000..b6107eeedf
--- /dev/null
+++ b/indra/newview/llkeyconflict.cpp
@@ -0,0 +1,1015 @@
+/**
+ * @file llkeyconflict.cpp
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2019, 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$
+ */
+
+/*
+ * App-wide preferences. Note that these are not per-user,
+ * because we need to load many preferences before we have
+ * a login name.
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llkeyconflict.h"
+
+#include "llinitparam.h"
+#include "llkeyboard.h"
+#include "lltrans.h"
+#include "llviewercontrol.h"
+#include "llviewerinput.h"
+#include "llviewermenu.h"
+#include "llxuiparser.h"
+
+static const std::string saved_settings_key_controls[] = { "placeholder" }; // add settings from gSavedSettings here
+
+static const std::string filename_default = "key_bindings.xml";
+static const std::string filename_temporary = "key_bindings_tmp.xml"; // used to apply uncommited changes on the go.
+
+// LLKeyboard::stringFromMask is meant for UI and is OS dependent,
+// so this class uses it's own version
+std::string string_from_mask(MASK mask)
+{
+ std::string res;
+ if ((mask & MASK_CONTROL) != 0)
+ {
+ res = "CTL";
+ }
+ if ((mask & MASK_ALT) != 0)
+ {
+ if (!res.empty()) res += "_";
+ res += "ALT";
+ }
+ if ((mask & MASK_SHIFT) != 0)
+ {
+ if (!res.empty()) res += "_";
+ res += "SHIFT";
+ }
+
+ if (mask == MASK_NONE)
+ {
+ res = "NONE";
+ }
+ return res;
+}
+
+std::string string_from_mouse(EMouseClickType click, bool translate)
+{
+ std::string res;
+ switch (click)
+ {
+ case CLICK_LEFT:
+ res = "LMB";
+ break;
+ case CLICK_MIDDLE:
+ res = "MMB";
+ break;
+ case CLICK_RIGHT:
+ res = "RMB";
+ break;
+ case CLICK_BUTTON4:
+ res = "MB4";
+ break;
+ case CLICK_BUTTON5:
+ res = "MB5";
+ break;
+ case CLICK_DOUBLELEFT:
+ res = "Double LMB";
+ break;
+ default:
+ break;
+ }
+
+ if (translate && !res.empty())
+ {
+ res = LLTrans::getString(res);
+ }
+ return res;
+}
+
+// LLKeyConflictHandler
+
+S32 LLKeyConflictHandler::sTemporaryFileUseCount = 0;
+
+LLKeyConflictHandler::LLKeyConflictHandler()
+: mHasUnsavedChanges(false),
+ mUsesTemporaryFile(false),
+ mLoadMode(MODE_COUNT)
+{
+}
+
+LLKeyConflictHandler::LLKeyConflictHandler(ESourceMode mode)
+: mHasUnsavedChanges(false),
+ mUsesTemporaryFile(false),
+ mLoadMode(mode)
+{
+ loadFromSettings(mode);
+}
+
+LLKeyConflictHandler::~LLKeyConflictHandler()
+{
+ clearUnsavedChanges();
+ // Note: does not reset bindings if temporary file was used
+}
+
+bool LLKeyConflictHandler::canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask)
+{
+ return mControlsMap[control_name].canHandle(mouse_ind, key, mask);
+}
+
+bool LLKeyConflictHandler::canHandleKey(const std::string &control_name, KEY key, MASK mask)
+{
+ return canHandleControl(control_name, CLICK_NONE, key, mask);
+}
+
+bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask)
+{
+ return canHandleControl(control_name, mouse_ind, KEY_NONE, mask);
+}
+
+bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask)
+{
+ return canHandleControl(control_name, (EMouseClickType)mouse_ind, KEY_NONE, mask);
+}
+
+bool LLKeyConflictHandler::canAssignControl(const std::string &control_name)
+{
+ control_map_t::iterator iter = mControlsMap.find(control_name);
+ if (iter != mControlsMap.end())
+ {
+ return iter->second.mAssignable;
+ }
+ // If we don't know this control, means it wasn't assigned by user yet and thus is editable
+ return true;
+}
+
+// static
+bool LLKeyConflictHandler::isReservedByMenu(const KEY &key, const MASK &mask)
+{
+ if (key == KEY_NONE)
+ {
+ return false;
+ }
+ return (gMenuBarView && gMenuBarView->hasAccelerator(key, mask))
+ || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(key, mask));
+}
+
+// static
+bool LLKeyConflictHandler::isReservedByMenu(const LLKeyData &data)
+{
+ if (data.mMouse != CLICK_NONE || data.mKey == KEY_NONE)
+ {
+ return false;
+ }
+ return (gMenuBarView && gMenuBarView->hasAccelerator(data.mKey, data.mMask))
+ || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(data.mKey, data.mMask));
+}
+
+bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
+{
+ if (control_name.empty())
+ {
+ return false;
+ }
+ LLKeyConflict &type_data = mControlsMap[control_name];
+ if (!type_data.mAssignable)
+ {
+ // Example: user tried to assign camera spin to all modes, but first person mode doesn't support it
+ return false;
+ }
+ LLKeyData data(mouse, key, mask, ignore_mask);
+ if (type_data.mKeyBind.getKeyData(index) == data)
+ {
+ return true;
+ }
+ if (isReservedByMenu(data))
+ {
+ return false;
+ }
+ if (removeConflicts(data, type_data.mConflictMask))
+ {
+ type_data.mKeyBind.replaceKeyData(data, index);
+ mHasUnsavedChanges = true;
+ return true;
+ }
+ // control already in use/blocked
+ return false;
+}
+
+bool LLKeyConflictHandler::clearControl(const std::string &control_name, U32 data_index)
+{
+ if (control_name.empty())
+ {
+ return false;
+ }
+ LLKeyConflict &type_data = mControlsMap[control_name];
+ if (!type_data.mAssignable)
+ {
+ // Example: user tried to assign camera spin to all modes, but first person mode doesn't support it
+ return false;
+ }
+ type_data.mKeyBind.resetKeyData(data_index);
+ mHasUnsavedChanges = true;
+ return true;
+}
+
+LLKeyData LLKeyConflictHandler::getControl(const std::string &control_name, U32 index)
+{
+ if (control_name.empty())
+ {
+ return LLKeyData();
+ }
+ return mControlsMap[control_name].getKeyData(index);
+}
+
+bool LLKeyConflictHandler::isControlEmpty(const std::string &control_name)
+{
+ if (control_name.empty())
+ {
+ return true;
+ }
+ return mControlsMap[control_name].mKeyBind.isEmpty();
+}
+
+// static
+std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata)
+{
+ std::string result;
+
+ if (keydata.mMask != MASK_NONE && keydata.mKey != KEY_NONE)
+ {
+ result = LLKeyboard::stringFromAccelerator(keydata.mMask, keydata.mKey);
+ }
+ else if (keydata.mKey != KEY_NONE)
+ {
+ result = LLKeyboard::stringFromKey(keydata.mKey);
+ }
+ else if (keydata.mMask != MASK_NONE)
+ {
+ result = LLKeyboard::stringFromAccelerator(keydata.mMask);
+ }
+
+ result += string_from_mouse(keydata.mMouse, true);
+
+ return result;
+}
+
+std::string LLKeyConflictHandler::getControlString(const std::string &control_name, U32 index)
+{
+ if (control_name.empty())
+ {
+ return "";
+ }
+ return getStringFromKeyData(mControlsMap[control_name].getKeyData(index));
+}
+
+void LLKeyConflictHandler::loadFromControlSettings(const std::string &name)
+{
+ LLControlVariablePtr var = gSavedSettings.getControl(name);
+ if (var)
+ {
+ LLKeyBind bind(var->getValue());
+ LLKeyConflict key(bind, true, 0);
+ mControlsMap[name] = key;
+ }
+}
+
+void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination)
+{
+ for (LLInitParam::ParamIterator::const_iterator it = keymode.bindings.begin(),
+ end_it = keymode.bindings.end();
+ it != end_it;
+ ++it)
+ {
+ KEY key;
+ MASK mask;
+ EMouseClickType mouse = CLICK_NONE;
+ if (it->mouse.isProvided())
+ {
+ LLViewerInput::mouseFromString(it->mouse.getValue(), &mouse);
+ }
+ if (it->key.getValue().empty())
+ {
+ key = KEY_NONE;
+ }
+ else
+ {
+ LLKeyboard::keyFromString(it->key, &key);
+ }
+ LLKeyboard::maskFromString(it->mask, &mask);
+ // Note: it->command is also the name of UI element, howhever xml we are loading from
+ // might not know all the commands, so UI will have to know what to fill by its own
+ // Assumes U32_MAX conflict mask, and is assignable by default,
+ // but assignability might have been overriden by generatePlaceholders.
+ LLKeyConflict &type_data = (*destination)[it->command];
+ type_data.mKeyBind.addKeyData(mouse, key, mask, true);
+ }
+}
+
+bool LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination)
+{
+ if (filename.empty())
+ {
+ return false;
+ }
+
+ bool res = false;
+
+ LLViewerInput::Keys keys;
+ LLSimpleXUIParser parser;
+
+ if (parser.readXUI(filename, keys)
+ && keys.validateBlock())
+ {
+ switch (load_mode)
+ {
+ case MODE_FIRST_PERSON:
+ if (keys.first_person.isProvided())
+ {
+ loadFromSettings(keys.first_person, destination);
+ res = true;
+ }
+ break;
+ case MODE_THIRD_PERSON:
+ if (keys.third_person.isProvided())
+ {
+ loadFromSettings(keys.third_person, destination);
+ res = true;
+ }
+ break;
+ case MODE_EDIT_AVATAR:
+ if (keys.edit_avatar.isProvided())
+ {
+ loadFromSettings(keys.edit_avatar, destination);
+ res = true;
+ }
+ break;
+ case MODE_SITTING:
+ if (keys.sitting.isProvided())
+ {
+ loadFromSettings(keys.sitting, destination);
+ res = true;
+ }
+ break;
+ default:
+ LL_ERRS() << "Not implememted mode " << load_mode << LL_ENDL;
+ break;
+ }
+ }
+ return res;
+}
+
+void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
+{
+ mControlsMap.clear();
+ mDefaultsMap.clear();
+
+ // E.X. In case we need placeholder keys for conflict resolution.
+ generatePlaceholders(load_mode);
+
+ if (load_mode == MODE_SAVED_SETTINGS)
+ {
+ // load settings clss knows about, but it also possible to load settings by name separately
+ const S32 size = std::extent::value;
+ for (U32 i = 0; i < size; i++)
+ {
+ loadFromControlSettings(saved_settings_key_controls[i]);
+ }
+ }
+ else
+ {
+ // load defaults
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default);
+ if (!loadFromSettings(load_mode, filename, &mDefaultsMap))
+ {
+ LL_WARNS() << "Failed to load default settings, aborting" << LL_ENDL;
+ return;
+ }
+
+ // load user's
+ filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
+ if (!gDirUtilp->fileExists(filename) || !loadFromSettings(load_mode, filename, &mControlsMap))
+ {
+ // mind placeholders
+ mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
+ }
+ }
+ mLoadMode = load_mode;
+}
+
+void LLKeyConflictHandler::saveToSettings(bool temporary)
+{
+ if (mControlsMap.empty())
+ {
+ return;
+ }
+
+ if (mLoadMode == MODE_SAVED_SETTINGS)
+ {
+ // Does not support 'temporary', preferences handle that themself
+ // so in case of saved settings we just do not clear mHasUnsavedChanges
+ control_map_t::iterator iter = mControlsMap.begin();
+ control_map_t::iterator end = mControlsMap.end();
+
+ for (; iter != end; ++iter)
+ {
+ if (iter->first.empty())
+ {
+ continue;
+ }
+
+ LLKeyConflict &key = iter->second;
+ key.mKeyBind.trimEmpty();
+ if (!key.mAssignable)
+ {
+ continue;
+ }
+
+ if (gSavedSettings.controlExists(iter->first))
+ {
+ gSavedSettings.setLLSD(iter->first, key.mKeyBind.asLLSD());
+ }
+ else if (!key.mKeyBind.empty())
+ {
+ // Note: this is currently not in use, might be better for load mechanics to ask for and retain control group
+ // otherwise settings loaded from other control groups will end in gSavedSettings
+ LL_INFOS() << "Creating new keybinding " << iter->first << LL_ENDL;
+ gSavedSettings.declareLLSD(iter->first, key.mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS);
+ }
+ }
+ }
+ else
+ {
+ // Determine what file to load and load full copy of that file
+ std::string filename;
+
+ if (temporary)
+ {
+ filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
+ if (!gDirUtilp->fileExists(filename))
+ {
+ filename.clear();
+ }
+ }
+
+ if (filename.empty())
+ {
+ filename = gDirUtilp->findFile(filename_default,
+ gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+ gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+ }
+
+ LLViewerInput::Keys keys;
+ LLSimpleXUIParser parser;
+
+ if (parser.readXUI(filename, keys)
+ && keys.validateBlock())
+ {
+ // replace category we edited
+
+ // mode is a HACK to correctly reset bindings without reparsing whole file and avoid doing
+ // own param container (which will face issues with inasseesible members of LLInitParam)
+ LLViewerInput::KeyMode mode;
+ LLViewerInput::KeyBinding binding;
+
+ control_map_t::iterator iter = mControlsMap.begin();
+ control_map_t::iterator end = mControlsMap.end();
+ for (; iter != end; ++iter)
+ {
+ // By default xml have (had) up to 6 elements per function
+ // eventually it will be cleaned up and UI will only shows 3 per function,
+ // so make sure to cleanup.
+ // Also this helps in keeping file small.
+ iter->second.mKeyBind.trimEmpty();
+ U32 size = iter->second.mKeyBind.getDataCount();
+ for (U32 i = 0; i < size; ++i)
+ {
+ if (iter->first.empty())
+ {
+ continue;
+ }
+
+ LLKeyConflict &key = iter->second;
+ key.mKeyBind.trimEmpty();
+ if (key.mKeyBind.empty() || !key.mAssignable)
+ {
+ continue;
+ }
+
+ LLKeyData data = key.mKeyBind.getKeyData(i);
+ // Still write empty LLKeyData to make sure we will maintain UI position
+ if (data.mKey == KEY_NONE)
+ {
+ // Might be better idea to be consistent and use NONE. LLViewerInput can work with both cases
+ binding.key = "";
+ }
+ else
+ {
+ binding.key = LLKeyboard::stringFromKey(data.mKey, false /*Do not localize*/);
+ }
+ binding.mask = string_from_mask(data.mMask);
+ if (data.mMouse == CLICK_NONE)
+ {
+ binding.mouse.setProvided(false);
+ }
+ else
+ {
+ // set() because 'optional', for compatibility purposes
+ // just copy old keys.xml and rename to key_bindings.xml, it should work
+ binding.mouse.set(string_from_mouse(data.mMouse, false), true);
+ }
+ binding.command = iter->first;
+ mode.bindings.add(binding);
+ }
+ }
+
+ switch (mLoadMode)
+ {
+ case MODE_FIRST_PERSON:
+ if (keys.first_person.isProvided())
+ {
+ keys.first_person.bindings.set(mode.bindings, true);
+ }
+ break;
+ case MODE_THIRD_PERSON:
+ if (keys.third_person.isProvided())
+ {
+ keys.third_person.bindings.set(mode.bindings, true);
+ }
+ break;
+ case MODE_EDIT_AVATAR:
+ if (keys.edit_avatar.isProvided())
+ {
+ keys.edit_avatar.bindings.set(mode.bindings, true);
+ }
+ break;
+ case MODE_SITTING:
+ if (keys.sitting.isProvided())
+ {
+ keys.sitting.bindings.set(mode.bindings, true);
+ }
+ break;
+ default:
+ LL_ERRS() << "Not implememted mode " << mLoadMode << LL_ENDL;
+ break;
+ }
+
+ if (temporary)
+ {
+ // write to temporary xml and use it for gViewerInput
+ filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
+ if (!mUsesTemporaryFile)
+ {
+ mUsesTemporaryFile = true;
+ sTemporaryFileUseCount++;
+ }
+ }
+ else
+ {
+ // write back to user's xml and use it for gViewerInput
+ filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
+ // Don't reset mUsesTemporaryFile, it will be reset at cleanup stage
+ }
+
+ LLXMLNodePtr output_node = new LLXMLNode("keys", false);
+ LLXUIParser parser;
+ parser.writeXUI(output_node, keys);
+
+ // Write the resulting XML to file
+ if (!output_node->isNull())
+ {
+ LLFILE *fp = LLFile::fopen(filename, "w");
+ if (fp != NULL)
+ {
+ LLXMLNode::writeHeaderToFile(fp);
+ output_node->writeToFile(fp);
+ fclose(fp);
+ }
+ }
+ // Now force a rebind for keyboard
+ if (gDirUtilp->fileExists(filename))
+ {
+ // Ideally instead of rebinding immediately we should shedule
+ // the rebind since single file can have multiple handlers,
+ // one per mode, saving simultaneously.
+ // Or whatever uses LLKeyConflictHandler should control the process.
+ gViewerInput.loadBindingsXML(filename);
+ }
+ }
+ }
+
+#if 1
+ // Legacy support
+ // Remove #if-#endif section half a year after DRTVWR-501 releases.
+ // Update legacy settings in settings.xml
+ // We only care for third person view since legacy settings can't store
+ // more than one mode.
+ // We are saving this even if we are in temporary mode - preferences
+ // will restore values on cancel
+ if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges)
+ {
+ bool value = canHandleMouse("walk_to", CLICK_DOUBLELEFT, MASK_NONE);
+ gSavedSettings.setBOOL("DoubleClickAutoPilot", value);
+
+ value = canHandleMouse("walk_to", CLICK_LEFT, MASK_NONE);
+ gSavedSettings.setBOOL("ClickToWalk", value);
+
+ // new method can save both toggle and push-to-talk values simultaneously,
+ // but legacy one can save only one. It also doesn't support mask.
+ LLKeyData data = getControl("toggle_voice", 0);
+ bool can_toggle = !data.isEmpty();
+ if (!can_toggle)
+ {
+ data = getControl("voice_follow_key", 0);
+ }
+
+ gSavedSettings.setBOOL("PushToTalkToggle", can_toggle);
+ if (data.isEmpty())
+ {
+ // legacy viewer has a bug that might crash it if NONE value is assigned.
+ // just reset to default
+ gSavedSettings.getControl("PushToTalkButton")->resetToDefault(false);
+ }
+ else
+ {
+ if (data.mKey != KEY_NONE)
+ {
+ gSavedSettings.setString("PushToTalkButton", LLKeyboard::stringFromKey(data.mKey));
+ }
+ else
+ {
+ std::string ctrl_value;
+ switch (data.mMouse)
+ {
+ case CLICK_MIDDLE:
+ ctrl_value = "MiddleMouse";
+ break;
+ case CLICK_BUTTON4:
+ ctrl_value = "MouseButton4";
+ break;
+ case CLICK_BUTTON5:
+ ctrl_value = "MouseButton5";
+ break;
+ default:
+ ctrl_value = "MiddleMouse";
+ break;
+ }
+ gSavedSettings.setString("PushToTalkButton", ctrl_value);
+ }
+ }
+ }
+#endif
+
+ if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges)
+ {
+ // Map floater should react to doubleclick if doubleclick for teleport is set
+ // Todo: Seems conterintuitive for map floater to share inworld controls
+ // after these changes release, discuss with UI UX engineer if this should just
+ // be set to 1 by default (before release this also doubles as legacy support)
+ bool value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE);
+ gSavedSettings.setBOOL("DoubleClickTeleport", value);
+ }
+
+ if (!temporary)
+ {
+ // will remove any temporary file if there were any
+ clearUnsavedChanges();
+ }
+}
+
+LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_name, U32 index)
+{
+ if (control_name.empty())
+ {
+ return LLKeyData();
+ }
+ if (mLoadMode == MODE_SAVED_SETTINGS)
+ {
+ LLControlVariablePtr var = gSavedSettings.getControl(control_name);
+ if (var)
+ {
+ return LLKeyBind(var->getDefault()).getKeyData(index);
+ }
+ return LLKeyData();
+ }
+ else
+ {
+ control_map_t::iterator iter = mDefaultsMap.find(control_name);
+ if (iter != mDefaultsMap.end())
+ {
+ return iter->second.mKeyBind.getKeyData(index);
+ }
+ return LLKeyData();
+ }
+}
+
+void LLKeyConflictHandler::resetToDefault(const std::string &control_name, U32 index)
+{
+ if (control_name.empty())
+ {
+ return;
+ }
+ LLKeyData data = getDefaultControl(control_name, index);
+
+ if (data != mControlsMap[control_name].getKeyData(index))
+ {
+ // reset controls that might have been switched to our current control
+ removeConflicts(data, mControlsMap[control_name].mConflictMask);
+ mControlsMap[control_name].setKeyData(data, index);
+ }
+}
+
+void LLKeyConflictHandler::resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts)
+{
+ if (control_name.empty())
+ {
+ return;
+ }
+ if (mLoadMode == MODE_SAVED_SETTINGS)
+ {
+ LLControlVariablePtr var = gSavedSettings.getControl(control_name);
+ if (var)
+ {
+ LLKeyBind bind(var->getDefault());
+ if (!ignore_conflicts)
+ {
+ for (S32 i = 0; i < bind.getDataCount(); ++i)
+ {
+ removeConflicts(bind.getKeyData(i), mControlsMap[control_name].mConflictMask);
+ }
+ }
+ mControlsMap[control_name].mKeyBind = bind;
+ }
+ else
+ {
+ mControlsMap[control_name].mKeyBind.clear();
+ }
+ }
+ else
+ {
+ control_map_t::iterator iter = mDefaultsMap.find(control_name);
+ if (iter != mDefaultsMap.end())
+ {
+ if (!ignore_conflicts)
+ {
+ for (S32 i = 0; i < iter->second.mKeyBind.getDataCount(); ++i)
+ {
+ removeConflicts(iter->second.mKeyBind.getKeyData(i), mControlsMap[control_name].mConflictMask);
+ }
+ }
+ mControlsMap[control_name].mKeyBind = iter->second.mKeyBind;
+ }
+ else
+ {
+ mControlsMap[control_name].mKeyBind.clear();
+ }
+ }
+}
+
+void LLKeyConflictHandler::resetToDefault(const std::string &control_name)
+{
+ // reset specific binding without ignoring conflicts
+ resetToDefaultAndResolve(control_name, false);
+}
+
+void LLKeyConflictHandler::resetToDefaults(ESourceMode mode)
+{
+ if (mode == MODE_SAVED_SETTINGS)
+ {
+ control_map_t::iterator iter = mControlsMap.begin();
+ control_map_t::iterator end = mControlsMap.end();
+
+ for (; iter != end; ++iter)
+ {
+ resetToDefaultAndResolve(iter->first, true);
+ }
+ }
+ else
+ {
+ mControlsMap.clear();
+ generatePlaceholders(mode);
+ mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
+ }
+
+ mHasUnsavedChanges = true;
+}
+
+void LLKeyConflictHandler::resetToDefaults()
+{
+ if (!empty())
+ {
+ resetToDefaults(mLoadMode);
+ }
+ else
+ {
+ // not optimal since:
+ // 1. We are not sure that mLoadMode was set
+ // 2. We are not sure if there are any changes in comparison to default
+ // 3. We are loading 'current' only to replace it
+ // but it is reliable and works Todo: consider optimizing.
+ loadFromSettings(mLoadMode);
+ resetToDefaults(mLoadMode);
+ }
+}
+
+void LLKeyConflictHandler::clear()
+{
+ if (clearUnsavedChanges())
+ {
+ // temporary file was removed, this means we were using it and need to reload keyboard's bindings
+ resetKeyboardBindings();
+ }
+ mControlsMap.clear();
+ mDefaultsMap.clear();
+}
+
+// static
+void LLKeyConflictHandler::resetKeyboardBindings()
+{
+ // Try to load User's bindings first
+ std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
+ if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))
+ {
+ // Failed to load custom bindings, try default ones
+ key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default);
+ if (!gViewerInput.loadBindingsXML(key_bindings_file))
+ {
+ LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL;
+ }
+ }
+}
+
+void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
+{
+ // These controls are meant to cause conflicts when user tries to assign same control somewhere else
+ // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks
+
+ if (load_mode == MODE_FIRST_PERSON)
+ {
+ // First person view doesn't support camera controls
+ // Note: might be better idea to just load these from control_table_contents_camera.xml
+ // or to pass from floaterpreferences when it loads said file
+ registerTemporaryControl("look_up");
+ registerTemporaryControl("look_down");
+ registerTemporaryControl("move_forward");
+ registerTemporaryControl("move_backward");
+ registerTemporaryControl("move_forward_fast");
+ registerTemporaryControl("move_backward_fast");
+ registerTemporaryControl("spin_over");
+ registerTemporaryControl("spin_under");
+ registerTemporaryControl("pan_up");
+ registerTemporaryControl("pan_down");
+ registerTemporaryControl("pan_left");
+ registerTemporaryControl("pan_right");
+ registerTemporaryControl("pan_in");
+ registerTemporaryControl("pan_out");
+ registerTemporaryControl("spin_around_ccw");
+ registerTemporaryControl("spin_around_cw");
+
+ // control_table_contents_editing.xml
+ registerTemporaryControl("edit_avatar_spin_ccw");
+ registerTemporaryControl("edit_avatar_spin_cw");
+ registerTemporaryControl("edit_avatar_spin_over");
+ registerTemporaryControl("edit_avatar_spin_under");
+ registerTemporaryControl("edit_avatar_move_forward");
+ registerTemporaryControl("edit_avatar_move_backward");
+
+ // no autopilot or teleport
+ registerTemporaryControl("walk_to");
+ registerTemporaryControl("teleport_to");
+ }
+
+ if (load_mode == MODE_EDIT_AVATAR)
+ {
+ // no autopilot or teleport
+ registerTemporaryControl("walk_to");
+ registerTemporaryControl("teleport_to");
+ }
+
+ if (load_mode == MODE_SITTING)
+ {
+ // no autopilot
+ registerTemporaryControl("walk_to");
+ }
+ else
+ {
+ // sitting related functions should only be avaliable in sitting mode
+ registerTemporaryControl("move_forward_sitting");
+ registerTemporaryControl("move_backward_sitting");
+ registerTemporaryControl("spin_over_sitting");
+ registerTemporaryControl("spin_under_sitting");
+ registerTemporaryControl("spin_around_ccw_sitting");
+ registerTemporaryControl("spin_around_cw_sitting");
+ }
+}
+
+bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask)
+{
+ if (conlict_mask == CONFLICT_NOTHING)
+ {
+ // Can't conflict
+ return true;
+ }
+ std::map conflict_list;
+ control_map_t::iterator cntrl_iter = mControlsMap.begin();
+ control_map_t::iterator cntrl_end = mControlsMap.end();
+ for (; cntrl_iter != cntrl_end; ++cntrl_iter)
+ {
+ S32 index = cntrl_iter->second.mKeyBind.findKeyData(data);
+ if (index >= 0
+ && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING
+ && (cntrl_iter->second.mConflictMask & conlict_mask) != 0)
+ {
+ if (cntrl_iter->second.mAssignable)
+ {
+ // Potentially we can have multiple conflict flags conflicting
+ // including unassignable keys.
+ // So record the conflict and find all others before doing any changes.
+ // Assume that there is only one conflict per bind
+ conflict_list[cntrl_iter->first] = index;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ std::map::iterator cnflct_iter = conflict_list.begin();
+ std::map::iterator cnflct_end = conflict_list.end();
+ for (; cnflct_iter != cnflct_end; ++cnflct_iter)
+ {
+ mControlsMap[cnflct_iter->first].mKeyBind.resetKeyData(cnflct_iter->second);
+ }
+ return true;
+}
+
+void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask)
+{
+ LLKeyConflict *type_data = &mControlsMap[control_name];
+ type_data->mAssignable = false;
+ type_data->mConflictMask = conflict_mask;
+ type_data->mKeyBind.addKeyData(mouse, key, mask, false);
+}
+
+void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name, U32 conflict_mask)
+{
+ LLKeyConflict *type_data = &mControlsMap[control_name];
+ type_data->mAssignable = false;
+ type_data->mConflictMask = conflict_mask;
+}
+
+bool LLKeyConflictHandler::clearUnsavedChanges()
+{
+ bool result = false;
+ mHasUnsavedChanges = false;
+
+ if (mUsesTemporaryFile)
+ {
+ mUsesTemporaryFile = false;
+ sTemporaryFileUseCount--;
+ if (!sTemporaryFileUseCount)
+ {
+ result = clearTemporaryFile();
+ }
+ // else: might be usefull to overwrite content of temp file with defaults
+ // but at the moment there is no such need
+ }
+ return result;
+}
+
+//static
+bool LLKeyConflictHandler::clearTemporaryFile()
+{
+ // At the moment single file needs five handlers (one per mode), so doing this
+ // will remove file for all hadlers
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
+ if (gDirUtilp->fileExists(filename))
+ {
+ LLFile::remove(filename);
+ return true;
+ }
+ return false;
+}
+
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
new file mode 100644
index 0000000000..2926ca3aeb
--- /dev/null
+++ b/indra/newview/llkeyconflict.h
@@ -0,0 +1,175 @@
+/**
+ * @file llkeyconflict.h
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2019, 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_LLKEYCONFLICT_H
+#define LL_LLKEYCONFLICT_H
+
+#include "llkeybind.h"
+#include "llviewerinput.h"
+
+
+class LLKeyConflict
+{
+public:
+ LLKeyConflict() : mAssignable(true), mConflictMask(U32_MAX) {} //temporary assignable, don't forget to change once all keys are recorded
+ LLKeyConflict(bool assignable, U32 conflict_mask)
+ : mAssignable(assignable), mConflictMask(conflict_mask) {}
+ LLKeyConflict(const LLKeyBind &bind, bool assignable, U32 conflict_mask)
+ : mAssignable(assignable), mConflictMask(conflict_mask), mKeyBind(bind) {}
+
+ LLKeyData getPrimaryKeyData() { return mKeyBind.getKeyData(0); }
+ LLKeyData getKeyData(U32 index) { return mKeyBind.getKeyData(index); }
+ void setPrimaryKeyData(const LLKeyData& data) { mKeyBind.replaceKeyData(data, 0); }
+ void setKeyData(const LLKeyData& data, U32 index) { mKeyBind.replaceKeyData(data, index); }
+ bool canHandle(EMouseClickType mouse, KEY key, MASK mask) { return mKeyBind.canHandle(mouse, key, mask); }
+
+ LLKeyBind mKeyBind;
+ bool mAssignable; // whether user can change key or key simply acts as placeholder
+ U32 mConflictMask;
+};
+
+class LLKeyConflictHandler
+{
+public:
+
+ enum ESourceMode // partially repeats e_keyboard_mode
+ {
+ MODE_FIRST_PERSON,
+ MODE_THIRD_PERSON,
+ MODE_EDIT_AVATAR,
+ MODE_SITTING,
+ MODE_SAVED_SETTINGS, // for settings from saved settings
+ MODE_COUNT
+ };
+
+ const U32 CONFLICT_NOTHING = 0;
+ // at the moment this just means that key will conflict with everything that is identical
+ const U32 CONFLICT_ANY = U32_MAX;
+
+ // Note: missed selection and edition commands (would be really nice to go through selection via MB4/5 or wheel)
+
+ LLKeyConflictHandler();
+ LLKeyConflictHandler(ESourceMode mode);
+ ~LLKeyConflictHandler();
+
+ bool canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask);
+ bool canHandleKey(const std::string &control_name, KEY key, MASK mask);
+ bool canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask);
+ bool canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask); //Just for convinience
+ bool canAssignControl(const std::string &control_name);
+ static bool isReservedByMenu(const KEY &key, const MASK &mask);
+ static bool isReservedByMenu(const LLKeyData &data);
+
+ // @control_name - see REGISTER_KEYBOARD_ACTION in llviewerinput for avaliable options,
+ // usually this is just name of the function
+ // @data_index - single control (function) can have multiple key combinations trigering
+ // it, this index indicates combination function will change/add; Note that preferences
+ // floater can only display up to 3 options, but data_index can be bigger than that
+ // @mouse_ind - mouse action (middle click, MB5 etc)
+ // @key - keyboard key action
+ // @mask - shift/ctrl/alt flags
+ // @ignore_mask - Either to expect exact match (ctrl+K will not trigger if ctrl+shift+K
+ // is active) or ignore not expected masks as long as expected mask is present
+ // (ctrl+K will be triggered if ctrl+shift+K is active)
+ bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
+ bool clearControl(const std::string &control_name, U32 data_index);
+
+ LLKeyData getControl(const std::string &control_name, U32 data_index);
+ bool isControlEmpty(const std::string &control_name);
+
+ // localized string
+ static std::string getStringFromKeyData(const LLKeyData& keydata);
+ std::string getControlString(const std::string &control_name, U32 data_index);
+
+ // Load single control, overrides existing one if names match
+ void loadFromControlSettings(const std::string &name);
+ // Drops any changes loads controls with ones from 'saved settings' or from xml
+ void loadFromSettings(ESourceMode load_mode);
+
+ // Saves settings to 'saved settings' or to xml
+ // If 'temporary' is set, function will save settings to temporary
+ // file and reload input bindings from temporary file.
+ // 'temporary' does not support gSavedSettings, those are handled
+ // by preferences, so 'temporary' is such case will simply not
+ // reset mHasUnsavedChanges
+ //
+ // 'temporary' exists to support ability of live-editing settings in
+ // preferences: temporary for testing changes 'live' without saving them,
+ // then hitting ok/cancel and save/discard values permanently.
+ void saveToSettings(bool apply_temporary = false);
+
+ LLKeyData getDefaultControl(const std::string &control_name, U32 data_index);
+ // Resets keybinding to default variant from 'saved settings' or xml
+ void resetToDefault(const std::string &control_name, U32 index);
+ void resetToDefault(const std::string &control_name);
+ // resets current mode to defaults
+ void resetToDefaults();
+
+ bool empty() { return mControlsMap.empty(); }
+ void clear();
+
+ // reloads bindings from last valid user's xml or from default xml
+ // to keyboard's handler
+ static void resetKeyboardBindings();
+
+ bool hasUnsavedChanges() { return mHasUnsavedChanges; }
+ void setLoadMode(ESourceMode mode) { mLoadMode = mode; }
+ ESourceMode getLoadMode() { return mLoadMode; }
+
+private:
+ void resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts);
+ void resetToDefaults(ESourceMode mode);
+
+ // at the moment these kind of control is not savable, but takes part in conflict resolution
+ void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
+ void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0);
+
+ typedef std::map control_map_t;
+ void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination);
+ bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
+ void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
+ // returns false in case user is trying to reuse control that can't be reassigned
+ bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask);
+
+ // removes flags and removes temporary file, returns 'true' if file was removed
+ bool clearUnsavedChanges();
+ // return true if there was a file to remove
+ static bool clearTemporaryFile();
+
+ control_map_t mControlsMap;
+ control_map_t mDefaultsMap;
+ bool mHasUnsavedChanges;
+ ESourceMode mLoadMode;
+
+ // To implement 'apply immediately'+revert on cancel, class applies changes to temporary file
+ // but this only works for settings from keybndings files (key_bindings.xml)
+ // saved setting rely onto external mechanism of preferences floater
+ bool mUsesTemporaryFile;
+ static S32 sTemporaryFileUseCount;
+};
+
+
+#endif // LL_LLKEYCONFLICT_H
diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp
index 56f20c7341..c47a1cd040 100644
--- a/indra/newview/llpreviewgesture.cpp
+++ b/indra/newview/llpreviewgesture.cpp
@@ -373,11 +373,11 @@ BOOL LLPreviewGesture::postBuild()
mReplaceEditor = edit;
combo = getChild( "modifier_combo");
- combo->setCommitCallback(onCommitSetDirty, this);
+ combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
mModifierCombo = combo;
combo = getChild( "key_combo");
- combo->setCommitCallback(onCommitSetDirty, this);
+ combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
mKeyCombo = combo;
list = getChild("library_list");
@@ -944,12 +944,18 @@ void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture)
break;
}
+ // Allow CTRL-F10 shortcut for gestures
+ //mModifierCombo->setEnabledByValue(CTRL_LABEL, gesture->mKey != KEY_F10);
+
mKeyCombo->setCurrentByIndex(0);
if (gesture->mKey != KEY_NONE)
{
mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey));
}
+ // Allow CTRL-F10 shortcut for gestures
+ //mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), gesture->mMask != MASK_CONTROL);
+
// Make UI steps for each gesture step
S32 i;
S32 count = gesture->mSteps.size();
@@ -1344,6 +1350,19 @@ LLMultiGesture* LLPreviewGesture::createGesture()
}
+void LLPreviewGesture::onCommitKeyorModifier()
+{
+ // SL-14139: ctrl-F10 is currently used to access top menu,
+ // so don't allow to bound gestures to this combination.
+
+ // Allow CTRL-F10 shortcut for gestures
+ //mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), mModifierCombo->getSimple() != CTRL_LABEL);
+ //mModifierCombo->setEnabledByValue(CTRL_LABEL, mKeyCombo->getSimple() != LLKeyboard::stringFromKey(KEY_F10));
+ //
+ mDirty = TRUE;
+ refresh();
+}
+
// static
void LLPreviewGesture::updateLabel(LLScrollListItem* item)
{
diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h
index 19bccf35bd..f5c47d71b8 100644
--- a/indra/newview/llpreviewgesture.h
+++ b/indra/newview/llpreviewgesture.h
@@ -101,6 +101,8 @@ protected:
LLScrollListItem* addStep(const enum EStepType step_type);
void onVisibilityChanged ( const LLSD& new_visibility );
+
+ void onCommitKeyorModifier();
static std::string getLabel(std::vector labels);
static void updateLabel(LLScrollListItem* item);
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
new file mode 100644
index 0000000000..4b36822e9a
--- /dev/null
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -0,0 +1,380 @@
+/**
+ * @file llsetkeybinddialog.cpp
+ * @brief LLSetKeyBindDialog class implementation.
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2019, 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 "llsetkeybinddialog.h"
+
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "lleventtimer.h"
+#include "llfloaterreg.h"
+#include "llfocusmgr.h"
+#include "llkeyconflict.h"
+#include "llviewercontrol.h"
+
+class LLSetKeyBindDialog::Updater : public LLEventTimer
+{
+public:
+
+ typedef boost::function callback_t;
+
+ Updater(callback_t cb, F32 period, MASK mask)
+ :LLEventTimer(period),
+ mMask(mask),
+ mCallback(cb)
+ {
+ mEventTimer.start();
+ }
+
+ virtual ~Updater(){}
+
+protected:
+ BOOL tick()
+ {
+ mCallback(mMask);
+ // Deletes itseft after execution
+ return TRUE;
+ }
+
+private:
+ MASK mMask;
+ callback_t mCallback;
+};
+
+bool LLSetKeyBindDialog::sRecordKeys = false;
+
+LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
+ : LLModalDialog(key),
+ pParent(NULL),
+ mKeyFilterMask(DEFAULT_KEY_FILTER),
+ pUpdater(NULL),
+ mLastMaskKey(0),
+ mContextConeOpacity(0.f),
+ mContextConeInAlpha(0.f),
+ mContextConeOutAlpha(0.f),
+ mContextConeFadeTime(0.f)
+{
+ mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
+ mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
+ mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
+}
+
+LLSetKeyBindDialog::~LLSetKeyBindDialog()
+{
+}
+
+//virtual
+BOOL LLSetKeyBindDialog::postBuild()
+{
+ childSetAction("SetEmpty", onBlank, this);
+ childSetAction("Default", onDefault, this);
+ childSetAction("Cancel", onCancel, this);
+ getChild("Cancel")->setFocus(TRUE);
+
+ pCheckBox = getChild("apply_all");
+ pDesription = getChild("descritption");
+
+ gFocusMgr.setKeystrokesOnly(TRUE);
+
+ return TRUE;
+}
+
+//virtual
+void LLSetKeyBindDialog::onOpen(const LLSD& data)
+{
+ sRecordKeys = true;
+ LLModalDialog::onOpen(data);
+}
+
+//virtual
+void LLSetKeyBindDialog::onClose(bool app_quiting)
+{
+ sRecordKeys = false;
+ if (pParent)
+ {
+ pParent->onCancelKeyBind();
+ pParent = NULL;
+ }
+ if (pUpdater)
+ {
+ // Doubleclick timer has't fired, delete it
+ delete pUpdater;
+ pUpdater = NULL;
+ }
+ LLModalDialog::onClose(app_quiting);
+}
+
+void LLSetKeyBindDialog::drawFrustum()
+{
+ static LLCachedControl max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
+ drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha);
+}
+
+//virtual
+void LLSetKeyBindDialog::draw()
+{
+ drawFrustum();
+ LLModalDialog::draw();
+}
+
+void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask)
+{
+ pParent = parent;
+ mFrustumOrigin = frustum_origin->getHandle();
+ mKeyFilterMask = key_mask;
+
+ std::string input;
+ if ((key_mask & ALLOW_MOUSE) != 0)
+ {
+ input = getString("mouse");
+ }
+ if ((key_mask & ALLOW_KEYS) != 0)
+ {
+ if (!input.empty())
+ {
+ input += ", ";
+ }
+ input += getString("keyboard");
+ }
+ pDesription->setText(getString("basic_description"));
+ pDesription->setTextArg("[INPUT]", input);
+}
+
+// static
+bool LLSetKeyBindDialog::recordKey(KEY key, MASK mask, BOOL down)
+{
+ if (sRecordKeys)
+ {
+ LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance("keybind_dialog", LLSD());
+ if (dialog && dialog->getVisible())
+ {
+ return dialog->recordAndHandleKey(key, mask, down);
+ }
+ else
+ {
+ LL_WARNS() << "Key recording was set despite no open dialog" << LL_ENDL;
+ sRecordKeys = false;
+ }
+ }
+ return false;
+}
+
+bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask, BOOL down)
+{
+ if ((key == 'Q' && mask == MASK_CONTROL)
+ || key == KEY_ESCAPE)
+ {
+ sRecordKeys = false;
+ closeFloater();
+ return true;
+ }
+
+ if (key == KEY_DELETE)
+ {
+ setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+ sRecordKeys = false;
+ closeFloater();
+ return false;
+ }
+
+ // forbidden keys
+ if (key == KEY_NONE
+ || key == KEY_RETURN
+ || key == KEY_BACKSPACE)
+ {
+ return false;
+ }
+
+ if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT)
+ {
+ // Mask keys get special treatment
+ if ((mKeyFilterMask & ALLOW_MASKS) == 0)
+ {
+ // Masks by themself are not allowed
+ return false;
+ }
+ if (down == TRUE)
+ {
+ // Most keys are handled on 'down' event because menu is handled on 'down'
+ // masks are exceptions to let other keys be handled
+ mLastMaskKey = key;
+ return false;
+ }
+ if (mLastMaskKey != key)
+ {
+ // This was mask+key combination that got rejected, don't handle mask's key
+ // Or user did something like: press shift, press ctrl, release shift
+ return false;
+ }
+ // Mask up event often generates things like 'shift key + shift mask', filter it out.
+ if (key == KEY_CONTROL)
+ {
+ mask &= ~MASK_CONTROL;
+ }
+ if (key == KEY_SHIFT)
+ {
+ mask &= ~MASK_SHIFT;
+ }
+ if (key == KEY_ALT)
+ {
+ mask &= ~MASK_ALT;
+ }
+ }
+ if ((mKeyFilterMask & ALLOW_KEYS) == 0)
+ {
+ // basic keys not allowed
+ return false;
+ }
+ else if ((mKeyFilterMask & ALLOW_MASK_KEYS) == 0 && mask != 0)
+ {
+ // masked keys not allowed
+ return false;
+ }
+
+ if (LLKeyConflictHandler::isReservedByMenu(key, mask))
+ {
+ pDesription->setText(getString("reserved_by_menu"));
+ pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key));
+ mLastMaskKey = 0;
+ return true;
+ }
+
+ setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
+ // Note/Todo: To warranty zero interference we should also consume
+ // an 'up' event if we recorded on 'down', not just close floater
+ // on first recorded combination.
+ sRecordKeys = false;
+ closeFloater();
+ return true;
+}
+
+BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
+{
+ BOOL result = FALSE;
+ if (!pParent)
+ {
+ // we already processed 'down' event, this is 'up', consume
+ closeFloater();
+ result = TRUE;
+ }
+ if (!result && clicktype == CLICK_LEFT)
+ {
+ // try handling buttons first
+ if (down)
+ {
+ result = LLView::handleMouseDown(x, y, mask);
+ }
+ else
+ {
+ result = LLView::handleMouseUp(x, y, mask);
+ }
+ if (result)
+ {
+ setFocus(TRUE);
+ gFocusMgr.setKeystrokesOnly(TRUE);
+ }
+ // ignore selection related combinations
+ else if (down && (mask & (MASK_SHIFT | MASK_CONTROL)) == 0)
+ {
+ // this can be a double click, wait a bit;
+ if (!pUpdater)
+ {
+ // Note: default doubleclick time is 500ms, but can stretch up to 5s
+ pUpdater = new Updater(boost::bind(&onClickTimeout, this, _1), 0.7f, mask);
+ result = TRUE;
+ }
+ }
+ }
+
+ if (!result
+ && (clicktype != CLICK_LEFT) // subcases were handled above
+ && ((mKeyFilterMask & ALLOW_MOUSE) != 0)
+ && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported
+ && ((mKeyFilterMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) // reserved for selection
+ {
+ setKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
+ result = TRUE;
+ if (!down)
+ {
+ // wait for 'up' event before closing
+ // alternative: set pUpdater
+ closeFloater();
+ }
+ }
+
+ return result;
+}
+
+//static
+void LLSetKeyBindDialog::onCancel(void* user_data)
+{
+ LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
+ self->closeFloater();
+}
+
+//static
+void LLSetKeyBindDialog::onBlank(void* user_data)
+{
+ LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
+ // tmp needs 'no key' button
+ self->setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+ self->closeFloater();
+}
+
+//static
+void LLSetKeyBindDialog::onDefault(void* user_data)
+{
+ LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
+ if (self->pParent)
+ {
+ self->pParent->onDefaultKeyBind(self->pCheckBox->getValue().asBoolean());
+ self->pParent = NULL;
+ }
+ self->closeFloater();
+}
+
+//static
+void LLSetKeyBindDialog::onClickTimeout(void* user_data, MASK mask)
+{
+ LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
+
+ // timer will delete itself after timeout
+ self->pUpdater = NULL;
+
+ self->setKeyBind(CLICK_LEFT, KEY_NONE, mask, self->pCheckBox->getValue().asBoolean());
+ self->closeFloater();
+}
+
+void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes)
+{
+ if (pParent)
+ {
+ pParent->onSetKeyBind(click, key, mask, all_modes);
+ pParent = NULL;
+ }
+}
+
diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h
new file mode 100644
index 0000000000..a34b952233
--- /dev/null
+++ b/indra/newview/llsetkeybinddialog.h
@@ -0,0 +1,106 @@
+/**
+ * @file llsetkeybinddialog.h
+ * @brief LLSetKeyBindDialog class definition
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2019, 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_LLSETKEYBINDDIALOG_H
+#define LL_LLSETKEYBINDDIALOG_H
+
+#include "llmodaldialog.h"
+
+class LLCheckBoxCtrl;
+class LLTextBase;
+
+// Filters for LLSetKeyBindDialog
+static const U32 ALLOW_MOUSE = 1;
+static const U32 ALLOW_MASK_MOUSE = 2;
+static const U32 ALLOW_KEYS = 4; //keyboard
+static const U32 ALLOW_MASK_KEYS = 8;
+static const U32 ALLOW_MASKS = 16;
+static const U32 DEFAULT_KEY_FILTER = ALLOW_MOUSE | ALLOW_MASK_MOUSE | ALLOW_KEYS | ALLOW_MASKS | ALLOW_MASK_KEYS;
+
+
+class LLKeyBindResponderInterface
+{
+public:
+ virtual ~LLKeyBindResponderInterface() {};
+
+ virtual void onCancelKeyBind() = 0;
+ virtual void onDefaultKeyBind(bool all_modes) = 0;
+ // returns true if parent failed to set key due to key being in use
+ virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) = 0;
+};
+
+class LLSetKeyBindDialog : public LLModalDialog
+{
+public:
+ LLSetKeyBindDialog(const LLSD& key);
+ ~LLSetKeyBindDialog();
+
+ /*virtual*/ BOOL postBuild();
+ /*virtual*/ void onOpen(const LLSD& data);
+ /*virtual*/ void onClose(bool app_quiting);
+ /*virtual*/ void draw();
+
+ void setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask = DEFAULT_KEY_FILTER);
+
+ // Wrapper around recordAndHandleKey
+ // It does not record, it handles, but handleKey function is already in use
+ static bool recordKey(KEY key, MASK mask, BOOL down);
+
+ BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
+ static void onCancel(void* user_data);
+ static void onBlank(void* user_data);
+ static void onDefault(void* user_data);
+ static void onClickTimeout(void* user_data, MASK mask);
+
+ class Updater;
+
+private:
+ bool recordAndHandleKey(KEY key, MASK mask, BOOL down);
+ void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
+ LLKeyBindResponderInterface *pParent;
+ LLCheckBoxCtrl *pCheckBox;
+ LLTextBase *pDesription;
+
+ U32 mKeyFilterMask;
+ Updater *pUpdater;
+ KEY mLastMaskKey;
+
+ static bool sRecordKeys; // for convinience and not to check instance each time
+
+ // drawFrustum
+private:
+ void drawFrustum();
+
+ LLHandle mFrustumOrigin;
+ F32 mContextConeOpacity;
+ F32 mContextConeInAlpha;
+ F32 mContextConeOutAlpha;
+ F32 mContextConeFadeTime;
+};
+
+
+#endif // LL_LLSETKEYBINDDIALOG_H
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index e1f617ace6..d1e3e9b943 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -372,7 +372,8 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a
if (vol_face.mJointRiggingInfoTab.needsUpdate())
{
S32 num_verts = vol_face.mNumVertices;
- if (num_verts>0 && vol_face.mWeights && (skin->mJointNames.size()>0))
+ S32 num_joints = skin->mJointNames.size();
+ if (num_verts > 0 && vol_face.mWeights && num_joints > 0)
{
initJointNums(const_cast(skin), avatar);
if (vol_face.mJointRiggingInfoTab.size()==0)
@@ -406,7 +407,7 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a
for (U32 k=0; k<4; ++k)
{
S32 joint_index = idx[k];
- if (wght[k] > 0.0f)
+ if (wght[k] > 0.0f && num_joints > joint_index)
{
S32 joint_num = skin->mJointNums[joint_index];
if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS)
@@ -457,35 +458,6 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a
}
}
-void LLSkinningUtil::updateRiggingInfo_(LLMeshSkinInfo* skin, LLVOAvatar *avatar, S32 num_verts, LLVector4a* weights, LLVector4a* positions, U8* joint_indices, LLJointRiggingInfoTab &rig_info_tab)
-{
- LL_RECORD_BLOCK_TIME(FTM_FACE_RIGGING_INFO);
- for (S32 i=0; i < num_verts; i++)
- {
- LLVector4a& pos = positions[i];
- LLVector4a& wght = weights[i];
- for (U32 k=0; k<4; ++k)
- {
- S32 joint_num = skin->mJointNums[joint_indices[k]];
- llassert(joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS);
- {
- rig_info_tab[joint_num].setIsRiggedTo(true);
- LLMatrix4a bind_shape;
- bind_shape.loadu(skin->mBindShapeMatrix);
- LLMatrix4a inv_bind;
- inv_bind.loadu(skin->mInvBindMatrix[joint_indices[k]]);
- LLMatrix4a mat;
- matMul(bind_shape, inv_bind, mat);
- LLVector4a pos_joint_space;
- mat.affineTransform(pos, pos_joint_space);
- pos_joint_space.mul(wght[k]);
- LLVector4a *extents = rig_info_tab[joint_num].getRiggedExtents();
- update_min_max(extents[0], extents[1], pos_joint_space);
- }
- }
- }
-}
-
// This is used for extracting rotation from a bind shape matrix that
// already has scales baked in
LLQuaternion LLSkinningUtil::getUnscaledQuaternion(const LLMatrix4& mat4)
diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h
index 0f25f96ed3..cb7653603b 100644
--- a/indra/newview/llskinningutil.h
+++ b/indra/newview/llskinningutil.h
@@ -70,7 +70,6 @@ namespace LLSkinningUtil
void initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar);
void updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face);
- void updateRiggingInfo_(LLMeshSkinInfo* skin, LLVOAvatar *avatar, S32 num_verts, LLVector4a* weights, LLVector4a* positions, U8* joint_indices, LLJointRiggingInfoTab &rig_info_tab);
LLQuaternion getUnscaledQuaternion(const LLMatrix4& mat4);
};
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 8a470cc97d..d32172a58e 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -1011,8 +1011,8 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
}
LLSpatialGroup* group = drawablep->getSpatialGroup();
- // avoid crash for race condition with unseating of an avatar
- // llassert(group != NULL);
+ //llassert(group != NULL);
+
if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
{
group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 5aba427bc7..7109ad6013 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2086,7 +2086,10 @@ bool idle_startup()
// update the voice settings *after* gCacheName initialization
// so that we can construct voice UI that relies on the name cache
- LLVoiceClient::getInstance()->updateSettings();
+ if (LLVoiceClient::instanceExists())
+ {
+ LLVoiceClient::getInstance()->updateSettings();
+ }
display_startup();
// OpenSim support: Init with defaults - we get the OpenSimExtras later during login
@@ -2504,8 +2507,12 @@ bool idle_startup()
LLAvatarTracker::instance().addBuddyList(list);
display_startup();
}
-
- LGGContactSets::getInstance()->loadFromDisk(); // [FS:CR] Load contact sets
+
+ // Contact sets
+ LGGContactSets* cs_instance = LGGContactSets::getInstance();
+ cs_instance->loadFromDisk();
+ LLAvatarNameCache::instance().setCustomNameCheckCallback(boost::bind(&LGGContactSets::checkCustomName, cs_instance, _1, _2, _3));
+ //
bool show_hud = false;
LLSD tutorial_setting = response["tutorial_setting"];
diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp
index c5e31ff8e6..5235914c34 100644
--- a/indra/newview/lltool.cpp
+++ b/indra/newview/lltool.cpp
@@ -60,7 +60,7 @@ LLTool::~LLTool()
}
}
-BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
+BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
{
BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
@@ -83,9 +83,9 @@ BOOL LLTool::handleMouseDown(S32 x, S32 y, MASK mask)
LL_INFOS() << "LLTool left mouse down" << LL_ENDL;
}
// by default, didn't handle it
+ // AGENT_CONTROL_LBUTTON_DOWN is handled by scanMouse() and scanKey()
// LL_INFOS() << "LLTool::handleMouseDown" << LL_ENDL;
- gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
- return TRUE;
+ return FALSE;
}
BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask)
@@ -95,8 +95,8 @@ BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask)
LL_INFOS() << "LLTool left mouse up" << LL_ENDL;
}
// by default, didn't handle it
+ // AGENT_CONTROL_LBUTTON_UP is handled by scanMouse() and scanKey()
// LL_INFOS() << "LLTool::handleMouseUp" << LL_ENDL;
- gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
return TRUE;
}
diff --git a/indra/newview/lltool.h b/indra/newview/lltool.h
index 308983afda..41a38804ce 100644
--- a/indra/newview/lltool.h
+++ b/indra/newview/lltool.h
@@ -49,7 +49,7 @@ public:
virtual BOOL isView() const { return FALSE; }
// Virtual functions inherited from LLMouseHandler
- virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down);
+ virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask);
diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp
index 76d2e3f9d2..122180731d 100644
--- a/indra/newview/lltoolfocus.cpp
+++ b/indra/newview/lltoolfocus.cpp
@@ -39,7 +39,7 @@
#include "llagentcamera.h"
#include "llbutton.h"
#include "llviewercontrol.h"
-#include "llviewerkeyboard.h"// Mouse movement by Singularity
+#include "llviewerinput.h"// Mouse movement by Singularity
#include "lldrawable.h"
#include "lltooltip.h"
#include "llhudmanager.h"
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index a342399d53..db298d144d 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -66,6 +66,7 @@
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
+#include "llviewerinput.h"
#include "llviewermedia.h"
#include "llvoavatarself.h"
#include "llviewermediafocus.h"
@@ -92,7 +93,6 @@ LLToolPie::LLToolPie()
mMouseOutsideSlop( false ),
mMouseSteerX(-1),
mMouseSteerY(-1),
- mBlockClickToWalk(false),
mClickAction(0),
mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ),
mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") ),
@@ -100,7 +100,7 @@ LLToolPie::LLToolPie()
{
}
-BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
+BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
{
BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
@@ -187,10 +187,8 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
mPick.mKeyMask = mask;
mMouseButtonDown = true;
-
- handleLeftClickPick();
- return TRUE;
+ return handleLeftClickPick();
}
// Spawn context menus on right mouse down so you can drag over and select
@@ -442,8 +440,6 @@ BOOL LLToolPie::handleLeftClickPick()
// put focus back "in world"
if (gFocusMgr.getKeyboardFocus())
{
- // don't click to walk on attempt to give focus to world
- mBlockClickToWalk = true;
gFocusMgr.setKeyboardFocus(NULL);
}
@@ -499,10 +495,7 @@ BOOL LLToolPie::handleLeftClickPick()
}
object = (LLViewerObject*)object->getParent();
}
- // FIRE-15189: Fix ClickToWalk not allowing mouse-walk (behavior change)
- //if (object && object == gAgentAvatarp && !gSavedSettings.getBOOL("ClickToWalk"))
if (object && object == gAgentAvatarp)
- //
{
// we left clicked on avatar, switch to focus mode
mMouseButtonDown = false;
@@ -520,7 +513,6 @@ BOOL LLToolPie::handleLeftClickPick()
// LLFirstUse::useLeftClickNoHit();
/////////
- // Eat the event
return LLTool::handleMouseDown(x, y, mask);
}
@@ -642,17 +634,140 @@ void LLToolPie::resetSelection()
mClickAction = 0;
}
-void LLToolPie::walkToClickedLocation()
+bool LLToolPie::walkToClickedLocation()
{
- if(mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
- mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
- mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
- mAutoPilotDestination->setPixelSize(5);
- mAutoPilotDestination->setColor(LLColor4U(170, 210, 190));
- mAutoPilotDestination->setDuration(3.f);
+ if (gAgent.getFlying() // don't auto-navigate while flying until that works
+ || !gAgentAvatarp
+ || gAgentAvatarp->isSitting())
+ {
+ return false;
+ }
- LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
- gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE);
+ LLPickInfo saved_pick = mPick;
+ if (gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
+ {
+ mPick = gViewerWindow->pickImmediate(mHoverPick.mMousePt.mX, mHoverPick.mMousePt.mY,
+ FALSE /* ignore transparent */,
+ FALSE /* ignore rigged */,
+ FALSE /* ignore particles */);
+ }
+ else
+ {
+ // We do not handle hover in mouselook as we do in other modes, so
+ // use croshair's position to do a pick
+ mPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2,
+ gViewerWindow->getWorldViewRectScaled().getHeight() / 2,
+ FALSE /* ignore transparent */,
+ FALSE /* ignore rigged */,
+ FALSE /* ignore particles */);
+ }
+
+ if (mPick.mPickType == LLPickInfo::PICK_OBJECT)
+ {
+ if (mPick.getObject() && mPick.getObject()->isHUDAttachment())
+ {
+ mPick = saved_pick;
+ return false;
+ }
+ }
+
+ LLViewerObject* avatar_object = mPick.getObject();
+
+ // get pointer to avatar
+ while (avatar_object && !avatar_object->isAvatar())
+ {
+ avatar_object = (LLViewerObject*)avatar_object->getParent();
+ }
+
+ if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+ {
+ const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
+ // pretend we picked some point a bit in front of avatar
+ mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
+ }
+
+ if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
+ (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero()))
+ {
+// [RLVa:KB] - Checked: RLVa-2.0.0
+ if (RlvActions::isRlvEnabled() && !RlvActions::canTeleportToLocal(mPick.mPosGlobal))
+ {
+ RlvUtil::notifyBlocked(RlvStringKeys::Blocked::AutoPilot);
+ mPick = saved_pick;
+ return false;
+ }
+// [/RLVa:KB]
+
+ gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
+
+ if (mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
+ mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
+ mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
+ mAutoPilotDestination->setPixelSize(5);
+ mAutoPilotDestination->setColor(LLColor4U(170, 210, 190));
+ mAutoPilotDestination->setDuration(3.f);
+
+ LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
+ gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE);
+ LLFirstUse::notMoving(false);
+ showVisualContextMenuEffect();
+ return true;
+ }
+ else
+ {
+ LL_DEBUGS() << "walk target was "
+ << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero")
+ << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land")
+ << ", pick object was " << mPick.mObjectID
+ << LL_ENDL;
+ mPick = saved_pick;
+ return false;
+ }
+ return true;
+}
+
+bool LLToolPie::teleportToClickedLocation()
+{
+ if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
+ {
+ // We do not handle hover in mouselook as we do in other modes, so
+ // use croshair's position to do a pick
+ BOOL pick_rigged = false;
+ mHoverPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2,
+ gViewerWindow->getWorldViewRectScaled().getHeight() / 2,
+ FALSE,
+ pick_rigged);
+ }
+ LLViewerObject* objp = mHoverPick.getObject();
+ LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
+
+ bool is_in_world = mHoverPick.mObjectID.notNull() && objp && !objp->isHUDAttachment();
+ bool is_land = mHoverPick.mPickType == LLPickInfo::PICK_LAND;
+ bool pos_non_zero = !mHoverPick.mPosGlobal.isExactlyZero();
+ bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch());
+ bool has_click_action = final_click_action(objp);
+
+ // FIRE-1765: Allow double-click walk/teleport to scripted objects
+ //if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action)))
+ bool allowDoubleClickOnScriptedObjects = gSavedSettings.getBOOL("FSAllowDoubleClickOnScriptedObjects");
+ if (pos_non_zero && (is_land || (is_in_world && ((allowDoubleClickOnScriptedObjects && objp->getClickAction() != CLICK_ACTION_SIT) || (!has_touch_handler && !has_click_action)))))
+ //
+ {
+// [RLVa:KB] - Checked: RLVa-2.0.0
+ if (RlvActions::isRlvEnabled() && !RlvActions::canTeleportToLocal(mPick.mPosGlobal))
+ {
+ RlvUtil::notifyBlocked(RlvStringKeys::Blocked::AutoPilot);
+ return false;
+ }
+// [/RLVa:KB]
+ LLVector3d pos = mHoverPick.mPosGlobal;
+ pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot();
+ gAgent.teleportViaLocationLookAt(pos);
+ mPick = mHoverPick;
+ showVisualContextMenuEffect();
+ return true;
+ }
+ return false;
}
// When we get object properties after left-clicking on an object
@@ -736,8 +851,9 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
}
else if (!mMouseOutsideSlop
- && mMouseButtonDown
- && gSavedSettings.getBOOL("ClickToWalk"))
+ && mMouseButtonDown
+ // disable camera steering if click on land is not used for moving
+ && gViewerInput.isMouseBindUsed(CLICK_LEFT))
{
S32 delta_x = x - mMouseDownX;
S32 delta_y = y - mMouseDownY;
@@ -835,84 +951,10 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
mDoubleClickTimer.reset();
}
LLViewerObject* obj = mPick.getObject();
- U8 click_action = final_click_action(obj);
- // let media have first pass at click
- if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus())
- {
- mBlockClickToWalk = true;
- }
stopCameraSteering();
mMouseButtonDown = false;
- if (click_action == CLICK_ACTION_NONE // not doing 1-click action
- && gSavedSettings.getBOOL("ClickToWalk") // click to walk enabled
- && !gAgent.getFlying() // don't auto-navigate while flying until that works
- && gAgentAvatarp
- && !gAgentAvatarp->isSitting()
- && !mBlockClickToWalk // another behavior hasn't cancelled click to walk
- )
- {
- // We may be doing click to walk, but we don't want to use a target on
- // a transparent object because the user thought they were clicking on
- // whatever they were seeing through it, so recompute what was clicked on
- // ignoring transparent objects
- LLPickInfo savedPick = mPick;
- mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
- FALSE /* ignore transparent */,
- FALSE /* ignore rigged */,
- FALSE /* ignore particles */);
-
-// if (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick
-// && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land
-// || mPick.mObjectID.notNull())) // or on an object
-// [RLVa:KB] - Checked: RLVa-2.0.0
- bool fValidPick = (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick
- && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land
- || mPick.mObjectID.notNull())); // or on an object
-
- if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) )
- {
- RlvUtil::notifyBlocked(RlvStringKeys::Blocked::AutoPilot);
- fValidPick = false;
- }
-
- if (fValidPick)
-// [/RLVa:KB]
- {
-
- // handle special cases of steering picks
- LLViewerObject* avatar_object = mPick.getObject();
-
- // get pointer to avatar
- while (avatar_object && !avatar_object->isAvatar())
- {
- avatar_object = (LLViewerObject*)avatar_object->getParent();
- }
-
- if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
- {
- const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
- // pretend we picked some point a bit in front of avatar
- mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
- }
- gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
- walkToClickedLocation();
- LLFirstUse::notMoving(false);
-
- return TRUE;
- }
- else
- {
- LL_DEBUGS("maint5901") << "walk target was "
- << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero")
- << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land")
- << ", pick object was " << mPick.mObjectID
- << LL_ENDL;
- // we didn't click to walk, so restore the original target
- mPick = savedPick;
- }
- }
gViewerWindow->setCursor(UI_CURSOR_ARROW);
if (hasMouseCapture())
{
@@ -922,7 +964,6 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
LLToolMgr::getInstance()->clearTransientTool();
gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on
- mBlockClickToWalk = false;
return LLTool::handleMouseUp(x, y, mask);
}
@@ -947,13 +988,11 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
{
return TRUE;
}
-
- // FIRE-1765: Allow double-click walk/teleport to scripted objects
- bool allowDoubleClickOnScriptedObjects = gSavedSettings.getBOOL("FSAllowDoubleClickOnScriptedObjects");
// FIRE-1765: Allow double-click walk/teleport to scripted objects
- //if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f))
- if (!allowDoubleClickOnScriptedObjects && (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f)))
+ //if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f))
+ bool allowDoubleClickOnScriptedObjects = gSavedSettings.getBOOL("FSAllowDoubleClickOnScriptedObjects");
+ if (!allowDoubleClickOnScriptedObjects && (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f)))
//
{
mDoubleClickTimer.stop();
@@ -961,74 +1000,6 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
}
mDoubleClickTimer.stop();
- if (gSavedSettings.getBOOL("DoubleClickAutoPilot"))
- {
- // We may be doing double click to walk, but we don't want to use a target on
- // a transparent object because the user thought they were clicking on
- // whatever they were seeing through it, so recompute what was clicked on
- // ignoring transparent objects
- LLPickInfo savedPick = mPick;
- mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
- FALSE /* ignore transparent */,
- FALSE /* ignore rigged */,
- FALSE /* ignore particles */);
-
- if(mPick.mPickType == LLPickInfo::PICK_OBJECT)
- {
- if (mPick.getObject() && mPick.getObject()->isHUDAttachment())
- {
- mPick = savedPick;
- return FALSE;
- }
- }
-
-// if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
-// (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero()))
-// [RLVa:KB] - Checked: RLVa-2.0.0
- bool fValidPick = ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
- (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero()));
-
- if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) )
- {
- RlvUtil::notifyBlocked(RlvStringKeys::Blocked::AutoPilot);
- fValidPick = false;
- }
-
- if (fValidPick)
-// [/RLVa:KB]
- {
- walkToClickedLocation();
- return TRUE;
- }
- else
- {
- // restore the original pick for any other purpose
- mPick = savedPick;
- }
- }
- else if (gSavedSettings.getBOOL("DoubleClickTeleport"))
- {
- LLViewerObject* objp = mPick.getObject();
- LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
-
- bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment();
- bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND;
- bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero();
- bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch());
- bool has_click_action = final_click_action(objp);
-
- // FIRE-1765: Allow double-click walk/teleport to scripted objects
- //if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action)))
- if (pos_non_zero && (is_land || (is_in_world && ((allowDoubleClickOnScriptedObjects && objp->getClickAction() != CLICK_ACTION_SIT) || (!has_touch_handler && !has_click_action)))))
- //
- {
- LLVector3d pos = mPick.mPosGlobal;
- pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot();
- gAgent.teleportViaLocationLookAt(pos);
- return TRUE;
- }
- }
-
return FALSE;
}
@@ -1782,7 +1753,6 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info)
void LLToolPie::handleSelect()
{
// tool is reselected when app gets focus, etc.
- mBlockClickToWalk = true;
}
void LLToolPie::handleDeselect()
@@ -1847,7 +1817,7 @@ void LLToolPie::stopCameraSteering()
bool LLToolPie::inCameraSteerMode()
{
- return mMouseButtonDown && mMouseOutsideSlop && gSavedSettings.getBOOL("ClickToWalk");
+ return mMouseButtonDown && mMouseOutsideSlop;
}
// true if x,y outside small box around start_x,start_y
@@ -2431,7 +2401,6 @@ void LLToolPie::startCameraSteering()
{
LLFirstUse::notMoving(false);
mMouseOutsideSlop = true;
- mBlockClickToWalk = true;
if (gAgentCamera.getFocusOnAvatar())
{
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 34640d7f9c..1f54e51589 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -42,7 +42,7 @@ class LLToolPie : public LLTool, public LLSingleton
public:
// Virtual functions inherited from LLMouseHandler
- virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down);
+ virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
@@ -71,8 +71,8 @@ public:
LLViewerObject* getClickActionObject() { return mClickActionObject; }
LLObjectSelection* getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; }
void resetSelection();
- void walkToClickedLocation();
- void blockClickToWalk() { mBlockClickToWalk = true; }
+ bool walkToClickedLocation();
+ bool teleportToClickedLocation();
void stopClickToWalk();
static void selectionPropertiesReceived();
@@ -121,7 +121,6 @@ private:
LLPointer mAutoPilotDestination;
LLPointer mMouseSteerGrabPoint;
bool mClockwise;
- bool mBlockClickToWalk;
LLUUID mMediaMouseCaptureID;
LLPickInfo mPick;
LLPickInfo mHoverPick;
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 10f7e074da..643c5b6b58 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -99,7 +99,7 @@
#include "llnotificationsutil.h"
#include "llpanelplaces.h"
#include "llstatusbar.h"
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "NACLantispam.h"
@@ -629,7 +629,10 @@ bool handleHighResSnapshotChanged(const LLSD& newvalue)
bool handleVoiceClientPrefsChanged(const LLSD& newvalue)
{
- LLVoiceClient::getInstance()->updateSettings();
+ if (LLVoiceClient::instanceExists())
+ {
+ LLVoiceClient::getInstance()->updateSettings();
+ }
return true;
}
@@ -876,23 +879,6 @@ void handleUsernameFormatOptionChanged(const LLSD& newvalue)
}
//
-// Allow instant change of keyboard layout
-void handleKeyboardLayoutChanged(const LLSD& newvalue)
-{
- std::string keyBindingFileName("keys.xml");
- if (newvalue.asBoolean())
- {
- keyBindingFileName = "keys_azerty.xml";
- }
-
- std::string key_bindings_file = gDirUtilp->findFile(keyBindingFileName,
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-
- gViewerKeyboard.loadBindingsXML(key_bindings_file);
-}
-//
-
// Global online status toggle
void handleGlobalOnlineStatusChanged(const LLSD& newvalue)
{
@@ -1278,8 +1264,6 @@ void settings_setup_listeners()
gSavedSettings.getControl("FSNameTagShowLegacyUsernames")->getCommitSignal()->connect(boost::bind(&handleUsernameFormatOptionChanged, _2));
gSavedSettings.getControl("FSTrimLegacyNames")->getCommitSignal()->connect(boost::bind(&handleLegacyTrimOptionChanged, _2));
- gSavedSettings.getControl("FSUseAzertyKeyboardLayout")->getCommitSignal()->connect(boost::bind(&handleKeyboardLayoutChanged, _2));
-
// [FS communication UI]
gSavedSettings.getControl("PlainTextChatHistory")->getSignal()->connect(boost::bind(&FSFloaterIM::processChatHistoryStyleUpdate, _2));
gSavedSettings.getControl("PlainTextChatHistory")->getSignal()->connect(boost::bind(&FSFloaterNearbyChat::processChatHistoryStyleUpdate, _2));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index e955166827..bd5a3e718e 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1427,8 +1427,9 @@ void render_ui(F32 zoom_factor, int subfield)
// Finalize scene
gPipeline.renderFinalize();
- LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
- render_hud_elements();
+ {// give unique scope
+ LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
+ render_hud_elements();
// [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay)
if (RlvActions::hasBehaviour(RLV_BHVR_SETOVERLAY))
{
@@ -1436,7 +1437,7 @@ void render_ui(F32 zoom_factor, int subfield)
}
// [/RLVa:KB]
render_hud_attachments();
-
+ } // unique scope
LLGLSDefault gls_default;
LLGLSUIDefault gls_ui;
{
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
new file mode 100644
index 0000000000..07a0bb302d
--- /dev/null
+++ b/indra/newview/llviewerinput.cpp
@@ -0,0 +1,1631 @@
+/**
+ * @file llviewerinput.cpp
+ * @brief LLViewerInput class implementation
+ *
+ * $LicenseInfo:firstyear=2005&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 "llviewerinput.h"
+
+#include "llappviewer.h"
+#include "llfloaterreg.h"
+#include "llmath.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+// [FS Communication UI]
+// #include "llfloaterimnearbychat.h"
+#include "fsnearbychathub.h"
+#include "lllineeditor.h"
+// [FS Communication UI]
+#include "llfocusmgr.h"
+#include "llkeybind.h" // LLKeyData
+#include "llmorphview.h"
+#include "llmoveview.h"
+#include "lltoolfocus.h"
+#include "lltoolpie.h"
+#include "llviewercontrol.h"
+#include "llviewerwindow.h"
+#include "llvoavatarself.h"
+#include "llfloatercamera.h"
+#include "llinitparam.h"
+#include "llselectmgr.h"
+#include "llfloaterwebcontent.h"
+#include "fsfloatersearch.h"
+#include "llvoiceclient.h"
+
+//
+// Constants
+//
+
+const F32 FLY_TIME = 0.5f;
+const F32 FLY_FRAMES = 4;
+
+const F32 NUDGE_TIME = 0.25f; // in seconds
+const S32 NUDGE_FRAMES = 2;
+const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed
+
+const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
+
+struct LLKeyboardActionRegistry
+: public LLRegistrySingleton, LLKeyboardActionRegistry>
+{
+ LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
+};
+
+LLViewerInput gViewerInput;
+
+bool agent_jump( EKeystate s )
+{
+ static BOOL first_fly_attempt(TRUE);
+ if (KEYSTATE_UP == s)
+ {
+ first_fly_attempt = TRUE;
+ return true;
+ }
+ F32 time = gKeyboard->getCurKeyElapsedTime();
+ S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
+
+ // Chalice Yao's crouch toggle
+ if (gSavedPerAccountSettings.getBOOL("FSCrouchToggleStatus"))
+ {
+ gSavedPerAccountSettings.setBOOL("FSCrouchToggleStatus", FALSE);
+ }
+ //
+
+ if( time < FLY_TIME
+ || frame_count <= FLY_FRAMES
+ || gAgent.upGrabbed()
+ || !gSavedSettings.getBOOL("AutomaticFly"))
+ {
+ gAgent.moveUp(1);
+ }
+ else
+ {
+ gAgent.setFlying(TRUE, first_fly_attempt);
+ first_fly_attempt = FALSE;
+ gAgent.moveUp(1);
+ }
+ return true;
+}
+
+bool agent_push_down( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ // Chalice Yao's crouch toggle
+ //gAgent.moveUp(-1);
+ else if (KEYSTATE_DOWN == s && !gAgent.getFlying() && !gAgentAvatarp->isSitting() && gSavedPerAccountSettings.getBOOL("FSCrouchToggle"))
+ {
+ if (gSavedPerAccountSettings.getBOOL("FSCrouchToggleStatus"))
+ {
+ gSavedPerAccountSettings.setBOOL("FSCrouchToggleStatus", FALSE);
+ }
+ else
+ {
+ gSavedPerAccountSettings.setBOOL("FSCrouchToggleStatus", TRUE);
+ gAgent.moveUp(-1);
+ }
+ }
+ else
+ {
+ gAgent.moveUp(-1);
+ }
+ //
+ return true;
+}
+
+static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode)
+{
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ if ( (gAgent.mDoubleTapRunMode == mode) && (gAgent.getTempRun()) )
+ gAgent.clearTempRun();
+// [/RLVa:KB]
+// if (gAgent.mDoubleTapRunMode == mode &&
+// gAgent.getRunning() &&
+// !gAgent.getAlwaysRun())
+// {
+// // Turn off temporary running.
+// gAgent.clearRunning();
+// gAgent.sendWalkRun(gAgent.getRunning());
+// }
+}
+
+static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode)
+{
+ if (KEYSTATE_UP == s)
+ {
+ // Note: in case shift is already released, slide left/right run
+ // will be released in agent_turn_left()/agent_turn_right()
+ agent_check_temporary_run(mode);
+ }
+ else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") &&
+ KEYSTATE_DOWN == s &&
+ !gAgent.getRunning())
+ {
+ if (gAgent.mDoubleTapRunMode == mode &&
+ gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME)
+ {
+ // Same walk-key was pushed again quickly; this is a
+ // double-tap so engage temporary running.
+// gAgent.setRunning();
+// gAgent.sendWalkRun(gAgent.getRunning());
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ gAgent.setTempRun();
+// [/RLVa:KB]
+ }
+
+ // Pressing any walk-key resets the double-tap timer
+ gAgent.mDoubleTapRunTimer.reset();
+ gAgent.mDoubleTapRunMode = mode;
+ }
+}
+
+static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
+{
+ agent_handle_doubletap_run(s, mode);
+ if (KEYSTATE_UP == s) return;
+
+ F32 time = gKeyboard->getCurKeyElapsedTime();
+ S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
+
+ if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
+ {
+ gAgent.moveAtNudge(direction);
+ }
+ else
+ {
+ gAgent.moveAt(direction);
+ }
+}
+
+bool camera_move_forward( EKeystate s );
+
+bool agent_push_forward( EKeystate s )
+{
+ if(gAgent.isMovementLocked()) return true;
+
+ //in free camera control mode we need to intercept keyboard events for avatar movements
+ if (LLFloaterCamera::inFreeCameraMode())
+ {
+ camera_move_forward(s);
+ }
+ else
+ {
+ agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD);
+ }
+ return true;
+}
+
+bool camera_move_backward( EKeystate s );
+
+bool agent_push_backward( EKeystate s )
+{
+ if(gAgent.isMovementLocked()) return true;
+
+ //in free camera control mode we need to intercept keyboard events for avatar movements
+ if (LLFloaterCamera::inFreeCameraMode())
+ {
+ camera_move_backward(s);
+ }
+ else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook"))
+ {
+ gAgentCamera.changeCameraToThirdPerson();
+ }
+ else
+ {
+ agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD);
+ }
+ return true;
+}
+
+static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
+{
+ agent_handle_doubletap_run(s, mode);
+ if( KEYSTATE_UP == s ) return;
+ F32 time = gKeyboard->getCurKeyElapsedTime();
+ S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
+
+ if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
+ {
+ gAgent.moveLeftNudge(direction);
+ }
+ else
+ {
+ gAgent.moveLeft(direction);
+ }
+}
+
+
+bool agent_slide_left( EKeystate s )
+{
+ if(gAgent.isMovementLocked()) return true;
+ agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT);
+ return true;
+}
+
+
+bool agent_slide_right( EKeystate s )
+{
+ if(gAgent.isMovementLocked()) return true;
+ agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT);
+ return true;
+}
+
+bool camera_spin_around_cw( EKeystate s );
+
+bool agent_turn_left(EKeystate s)
+{
+ //in free camera control mode we need to intercept keyboard events for avatar movements
+ if (LLFloaterCamera::inFreeCameraMode())
+ {
+ camera_spin_around_cw(s);
+ return true;
+ }
+
+ if(gAgent.isMovementLocked()) return false;
+
+ if (LLToolCamera::getInstance()->mouseSteerMode())
+ {
+ agent_slide_left(s);
+ }
+ else
+ {
+ if (KEYSTATE_UP == s)
+ {
+ // Check temporary running. In case user released 'left' key with shift already released.
+ agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT);
+ return true;
+ }
+ F32 time = gKeyboard->getCurKeyElapsedTime();
+ gAgent.moveYaw( LLFloaterMove::getYawRate( time ) );
+ }
+ return true;
+}
+
+bool camera_spin_around_ccw( EKeystate s );
+
+bool agent_turn_right( EKeystate s )
+{
+ //in free camera control mode we need to intercept keyboard events for avatar movements
+ if (LLFloaterCamera::inFreeCameraMode())
+ {
+ camera_spin_around_ccw(s);
+ return true;
+ }
+
+ if(gAgent.isMovementLocked()) return false;
+
+ if (LLToolCamera::getInstance()->mouseSteerMode())
+ {
+ agent_slide_right(s);
+ }
+ else
+ {
+ if (KEYSTATE_UP == s)
+ {
+ // Check temporary running. In case user released 'right' key with shift already released.
+ agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT);
+ return true;
+ }
+ F32 time = gKeyboard->getCurKeyElapsedTime();
+ gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) );
+ }
+ return true;
+}
+
+bool agent_look_up( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgent.movePitch(-1);
+ //gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+ return true;
+}
+
+
+bool agent_look_down( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgent.movePitch(1);
+ //gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+ return true;
+}
+
+bool agent_toggle_fly( EKeystate s )
+{
+ // Only catch the edge
+ if (KEYSTATE_DOWN == s )
+ {
+ LLAgent::toggleFlying();
+ }
+ return true;
+}
+
+F32 get_orbit_rate()
+{
+ F32 time = gKeyboard->getCurKeyElapsedTime();
+ if( time < NUDGE_TIME )
+ {
+ F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
+ //LL_INFOS() << rate << LL_ENDL;
+ return rate;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+bool camera_spin_around_ccw( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+ return true;
+}
+
+
+bool camera_spin_around_cw( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+ return true;
+}
+
+bool camera_spin_around_ccw_sitting( EKeystate s )
+{
+ if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return true;
+ if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
+ {
+ //send keystrokes, but do not change camera
+ agent_turn_right(s);
+ }
+ else
+ {
+ //change camera but do not send keystrokes
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+ }
+ return true;
+}
+
+
+bool camera_spin_around_cw_sitting( EKeystate s )
+{
+ if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return true;
+ if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
+ {
+ //send keystrokes, but do not change camera
+ agent_turn_left(s);
+ }
+ else
+ {
+ //change camera but do not send keystrokes
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+ }
+ return true;
+}
+
+
+bool camera_spin_over( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+ return true;
+}
+
+
+bool camera_spin_under( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+ return true;
+}
+
+bool camera_spin_over_sitting( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled())
+ {
+ //send keystrokes, but do not change camera
+ agent_jump(s);
+ }
+ else
+ {
+ //change camera but do not send keystrokes
+ gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+ }
+ return true;
+}
+
+
+bool camera_spin_under_sitting( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled())
+ {
+ //send keystrokes, but do not change camera
+ agent_push_down(s);
+ }
+ else
+ {
+ //change camera but do not send keystrokes
+ gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+ }
+ return true;
+}
+
+bool camera_move_forward( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitInKey( get_orbit_rate() );
+ return true;
+}
+
+
+bool camera_move_backward( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+ return true;
+}
+
+bool camera_move_forward_sitting( EKeystate s )
+{
+ if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return true;
+ if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
+ {
+ agent_push_forward(s);
+ }
+ else
+ {
+ gAgentCamera.setOrbitInKey( get_orbit_rate() );
+ }
+ return true;
+}
+
+bool camera_move_backward_sitting( EKeystate s )
+{
+ if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return true;
+
+ if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
+ {
+ agent_push_backward(s);
+ }
+ else
+ {
+ gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+ }
+ return true;
+}
+
+bool camera_pan_up( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanUpKey( get_orbit_rate() );
+ return true;
+}
+
+bool camera_pan_down( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanDownKey( get_orbit_rate() );
+ return true;
+}
+
+bool camera_pan_left( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanLeftKey( get_orbit_rate() );
+ return true;
+}
+
+bool camera_pan_right( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanRightKey( get_orbit_rate() );
+ return true;
+}
+
+bool camera_pan_in( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanInKey( get_orbit_rate() );
+ return true;
+}
+
+bool camera_pan_out( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanOutKey( get_orbit_rate() );
+ return true;
+}
+
+bool camera_move_forward_fast( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitInKey(2.5f);
+ return true;
+}
+
+bool camera_move_backward_fast( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitOutKey(2.5f);
+ return true;
+}
+
+
+bool edit_avatar_spin_ccw( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gMorphView->setCameraDrivenByKeys( TRUE );
+ gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+ //gMorphView->orbitLeft( get_orbit_rate() );
+ return true;
+}
+
+
+bool edit_avatar_spin_cw( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gMorphView->setCameraDrivenByKeys( TRUE );
+ gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+ //gMorphView->orbitRight( get_orbit_rate() );
+ return true;
+}
+
+bool edit_avatar_spin_over( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gMorphView->setCameraDrivenByKeys( TRUE );
+ gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+ //gMorphView->orbitUp( get_orbit_rate() );
+ return true;
+}
+
+
+bool edit_avatar_spin_under( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gMorphView->setCameraDrivenByKeys( TRUE );
+ gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+ //gMorphView->orbitDown( get_orbit_rate() );
+ return true;
+}
+
+bool edit_avatar_move_forward( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gMorphView->setCameraDrivenByKeys( TRUE );
+ gAgentCamera.setOrbitInKey( get_orbit_rate() );
+ //gMorphView->orbitIn();
+ return true;
+}
+
+
+bool edit_avatar_move_backward( EKeystate s )
+{
+ if( KEYSTATE_UP == s ) return true;
+ gMorphView->setCameraDrivenByKeys( TRUE );
+ gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+ //gMorphView->orbitOut();
+ return true;
+}
+
+bool stop_moving( EKeystate s )
+{
+ //it's supposed that 'stop moving' key will be held down for some time
+ if( KEYSTATE_UP == s ) return true;
+ // stop agent
+ gAgent.setControlFlags(AGENT_CONTROL_STOP);
+
+ // cancel autopilot
+ gAgent.stopAutoPilot();
+ return true;
+}
+
+bool start_chat( EKeystate s )
+{
+ if (LLAppViewer::instance()->quitRequested())
+ {
+ return true; // can't talk, gotta go, kthxbye!
+ }
+ if (KEYSTATE_DOWN != s) return true;
+
+ // start chat
+ // [FS Communication UI]
+ //LLFloaterIMNearbyChat::startChat(NULL);
+ FSNearbyChat::instance().showDefaultChatBar(TRUE);
+ // [FS Communication UI]
+ return true;
+}
+
+bool start_gesture( EKeystate s )
+{
+ // If avatar is pointing at something, don't start gesture.
+ // This works around the bug with Shared Media prims.
+ if (gAgentCamera.mPointAtObject)
+ {
+ return true;
+ }
+
+ // FIRE-4167: Don't start gesture if a floater with web content has focus
+ LLFloater* focused_floater = gFloaterView->getFocusedFloater();
+ if (focused_floater && (dynamic_cast(focused_floater) || dynamic_cast(focused_floater)))
+ {
+ return true;
+ }
+
+ LLUICtrl* focus_ctrlp = dynamic_cast(gFocusMgr.getKeyboardFocus());
+ if (KEYSTATE_UP == s &&
+ ! (focus_ctrlp && focus_ctrlp->acceptsTextInput()))
+ {
+ // [FS Communication UI]
+ //if ((LLFloaterReg::getTypedInstance("nearby_chat"))->getCurrentChat().empty())
+ //{
+ // // No existing chat in chat editor, insert '/'
+ // LLFloaterIMNearbyChat::startChat("/");
+ //}
+ //else
+ //{
+ // // Don't overwrite existing text in chat editor
+ // LLFloaterIMNearbyChat::startChat(NULL);
+ //}
+
+ FSNearbyChat::instance().showDefaultChatBar(TRUE, "/");
+ // [FS Communication UI]
+ }
+ return true;
+}
+
+bool run_forward(EKeystate s)
+{
+ if (KEYSTATE_UP != s)
+ {
+ if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD)
+ {
+ gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_FORWARD;
+ }
+ if (!gAgent.getRunning())
+ {
+// gAgent.setRunning();
+// gAgent.sendWalkRun(true);
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ gAgent.setTempRun();
+// [/RLVa:KB]
+ }
+ }
+ else if(KEYSTATE_UP == s)
+ {
+ if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_FORWARD)
+ gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
+// gAgent.clearRunning();
+// gAgent.sendWalkRun(false);
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ gAgent.clearTempRun();
+// [/RLVa:KB]
+ }
+ agent_push_forward(s);
+ return true;
+}
+
+bool run_backward(EKeystate s)
+{
+ if (KEYSTATE_UP != s)
+ {
+ if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD)
+ {
+ gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_BACKWARD;
+ }
+ if (!gAgent.getRunning())
+ {
+// gAgent.setRunning();
+// gAgent.sendWalkRun(true);
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ gAgent.setTempRun();
+// [/RLVa:KB]
+ }
+ }
+ else if (KEYSTATE_UP == s)
+ {
+ if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_BACKWARD)
+ gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
+// gAgent.clearRunning();
+// gAgent.sendWalkRun(false);
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ gAgent.clearTempRun();
+// [/RLVa:KB]
+ }
+ agent_push_backward(s);
+ return true;
+}
+
+bool run_left(EKeystate s)
+{
+ if (KEYSTATE_UP != s)
+ {
+ if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT)
+ {
+ gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDELEFT;
+ }
+ if (!gAgent.getRunning())
+ {
+// gAgent.setRunning();
+// gAgent.sendWalkRun(true);
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ gAgent.setTempRun();
+// [/RLVa:KB]
+ }
+ }
+ else if (KEYSTATE_UP == s)
+ {
+ if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDELEFT)
+ gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
+// gAgent.clearRunning();
+// gAgent.sendWalkRun(false);
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ gAgent.clearTempRun();
+// [/RLVa:KB]
+ }
+ agent_slide_left(s);
+ return true;
+}
+
+bool run_right(EKeystate s)
+{
+ if (KEYSTATE_UP != s)
+ {
+ if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT)
+ {
+ gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDERIGHT;
+ }
+ if (!gAgent.getRunning())
+ {
+// gAgent.setRunning();
+// gAgent.sendWalkRun(true);
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ gAgent.setTempRun();
+// [/RLVa:KB]
+ }
+ }
+ else if (KEYSTATE_UP == s)
+ {
+ if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDERIGHT)
+ gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
+// gAgent.clearRunning();
+// gAgent.sendWalkRun(false);
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+ gAgent.clearTempRun();
+// [/RLVa:KB]
+ }
+ agent_slide_right(s);
+ return true;
+}
+
+bool toggle_run(EKeystate s)
+{
+ if (KEYSTATE_DOWN != s) return true;
+ bool run = gAgent.getAlwaysRun();
+ if (run)
+ {
+ gAgent.clearAlwaysRun();
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+// gAgent.clearRunning();
+// [/RLVa:KB]
+ }
+ else
+ {
+ gAgent.setAlwaysRun();
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+// gAgent.setRunning();
+// [/RLVa:KB]
+ }
+// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
+// gAgent.sendWalkRun(!run);
+// [/RLVa:KB]
+ return true;
+}
+
+bool toggle_sit(EKeystate s)
+{
+ if (KEYSTATE_DOWN != s) return true;
+ if (gAgent.isSitting())
+ {
+ gAgent.standUp();
+ }
+ else
+ {
+ gAgent.sitDown();
+ }
+ return true;
+}
+
+bool toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
+{
+ if (KEYSTATE_DOWN != s) return true;
+ bool pause = LLViewerMedia::getInstance()->isAnyMediaPlaying();
+ LLViewerMedia::getInstance()->setAllMediaPaused(pause);
+ return true;
+}
+
+bool toggle_enable_media(EKeystate s)
+{
+ if (KEYSTATE_DOWN != s) return true;
+ bool pause = LLViewerMedia::getInstance()->isAnyMediaPlaying() || LLViewerMedia::getInstance()->isAnyMediaShowing();
+ LLViewerMedia::getInstance()->setAllMediaEnabled(!pause);
+ return true;
+}
+
+bool walk_to(EKeystate s)
+{
+ if (KEYSTATE_DOWN != s) return true;
+ return LLToolPie::getInstance()->walkToClickedLocation();
+}
+
+bool teleport_to(EKeystate s)
+{
+ if (KEYSTATE_DOWN != s) return true;
+ return LLToolPie::getInstance()->teleportToClickedLocation();
+}
+
+bool toggle_voice(EKeystate s)
+{
+ if (KEYSTATE_DOWN != s) return true;
+ if (!LLAgent::isActionAllowed("speak")) return false;
+ LLVoiceClient::getInstance()->toggleUserPTTState();
+ return true;
+}
+
+bool voice_follow_key(EKeystate s)
+{
+ if (KEYSTATE_DOWN == s)
+ {
+ if (!LLAgent::isActionAllowed("speak")) return false;
+ LLVoiceClient::getInstance()->setUserPTTState(true);
+ return true;
+ }
+ else if (KEYSTATE_UP == s && LLVoiceClient::getInstance()->getUserPTTState())
+ {
+ LLVoiceClient::getInstance()->setUserPTTState(false);
+ return true;
+ }
+ return false;
+}
+
+bool agen_control_lbutton_handle(EKeystate s)
+{
+ switch (s)
+ {
+ case KEYSTATE_DOWN:
+ gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
+ break;
+ case KEYSTATE_UP:
+ gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
+REGISTER_KEYBOARD_ACTION("jump", agent_jump);
+REGISTER_KEYBOARD_ACTION("push_down", agent_push_down);
+REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
+REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward);
+REGISTER_KEYBOARD_ACTION("look_up", agent_look_up);
+REGISTER_KEYBOARD_ACTION("look_down", agent_look_down);
+REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly);
+REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left);
+REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right);
+REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left);
+REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw);
+REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over);
+REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under);
+REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting);
+REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting);
+REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward);
+REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward);
+REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting);
+REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting);
+REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up);
+REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down);
+REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left);
+REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right);
+REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in);
+REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out);
+REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast);
+REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under);
+REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward);
+REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward);
+REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving);
+REGISTER_KEYBOARD_ACTION("start_chat", start_chat);
+REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture);
+REGISTER_KEYBOARD_ACTION("run_forward", run_forward);
+REGISTER_KEYBOARD_ACTION("run_backward", run_backward);
+REGISTER_KEYBOARD_ACTION("run_left", run_left);
+REGISTER_KEYBOARD_ACTION("run_right", run_right);
+REGISTER_KEYBOARD_ACTION("toggle_run", toggle_run);
+REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit);
+REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
+REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
+REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
+REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
+REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice);
+REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key);
+#undef REGISTER_KEYBOARD_ACTION
+
+LLViewerInput::LLViewerInput()
+{
+ resetBindings();
+
+ for (S32 i = 0; i < KEY_COUNT; i++)
+ {
+ mKeyHandledByUI[i] = FALSE;
+ }
+ for (S32 i = 0; i < CLICK_COUNT; i++)
+ {
+ mMouseLevel[i] = MOUSE_STATE_SILENT;
+ }
+ // we want the UI to never see these keys so that they can always control the avatar/camera
+ for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++)
+ {
+ mKeysSkippedByUI.insert(k);
+ }
+}
+
+// static
+BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode)
+{
+ if (string == "FIRST_PERSON")
+ {
+ *mode = MODE_FIRST_PERSON;
+ return TRUE;
+ }
+ else if (string == "THIRD_PERSON")
+ {
+ *mode = MODE_THIRD_PERSON;
+ return TRUE;
+ }
+ else if (string == "EDIT_AVATAR")
+ {
+ *mode = MODE_EDIT_AVATAR;
+ return TRUE;
+ }
+ else if (string == "SITTING")
+ {
+ *mode = MODE_SITTING;
+ return TRUE;
+ }
+ else
+ {
+ *mode = MODE_THIRD_PERSON;
+ return FALSE;
+ }
+}
+
+// static
+BOOL LLViewerInput::mouseFromString(const std::string& string, EMouseClickType *mode)
+{
+ if (string == "LMB")
+ {
+ *mode = CLICK_LEFT;
+ return TRUE;
+ }
+ else if (string == "Double LMB")
+ {
+ *mode = CLICK_DOUBLELEFT;
+ return TRUE;
+ }
+ else if (string == "MMB")
+ {
+ *mode = CLICK_MIDDLE;
+ return TRUE;
+ }
+ else if (string == "MB4")
+ {
+ *mode = CLICK_BUTTON4;
+ return TRUE;
+ }
+ else if (string == "MB5")
+ {
+ *mode = CLICK_BUTTON5;
+ return TRUE;
+ }
+ else
+ {
+ *mode = CLICK_NONE;
+ return FALSE;
+ }
+}
+
+BOOL LLViewerInput::handleKey(KEY translated_key, MASK translated_mask, BOOL repeated)
+{
+ // check for re-map
+ EKeyboardMode mode = gViewerInput.getMode();
+ U32 keyidx = (translated_mask<<16) | translated_key;
+ key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx);
+ if (iter != mRemapKeys[mode].end())
+ {
+ translated_key = (iter->second) & 0xff;
+ translated_mask = (iter->second)>>16;
+ }
+
+ // No repeats of F-keys
+ BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12);
+ if (!repeatable_key && repeated)
+ {
+ return FALSE;
+ }
+
+ LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL;
+ // skip skipped keys
+ if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end())
+ {
+ mKeyHandledByUI[translated_key] = FALSE;
+ //LL_INFOS("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL;
+ LL_INFOS_ONCE("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL; // Change log message to not print out every time
+ }
+ else
+ {
+ // it is sufficient to set this value once per call to handlekey
+ // without clearing it, as it is only used in the subsequent call to scanKey
+ mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask);
+ // mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress)
+ // NOT whether some UI shortcut wishes to handle the keypress
+
+ }
+ return mKeyHandledByUI[translated_key];
+}
+
+BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask)
+{
+ return gViewerWindow->handleKeyUp(translated_key, translated_mask);
+}
+
+BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
+{
+ S32 index;
+ typedef boost::function function_t;
+ function_t function = NULL;
+ std::string name;
+
+ // Allow remapping of F2-F12
+ if (function_name[0] == 'F')
+ {
+ int c1 = function_name[1] - '0';
+ int c2 = function_name[2] ? function_name[2] - '0' : -1;
+ if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9)
+ {
+ int idx = c1;
+ if (c2 >= 0)
+ idx = idx*10 + c2;
+ if (idx >=2 && idx <= 12)
+ {
+ U32 keyidx = ((mask<<16)|key);
+ (mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1)));
+ return TRUE;
+ }
+ }
+ }
+
+ // Not remapped, look for a function
+
+ function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+ if (result)
+ {
+ function = *result;
+ }
+
+ if (!function)
+ {
+ LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+ return FALSE;
+ }
+
+ // check for duplicate first and overwrite
+ S32 size = mKeyBindings[mode].size();
+ for (index = 0; index < size; index++)
+ {
+ if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
+ break;
+ }
+
+ if (mode >= MODE_COUNT)
+ {
+ LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
+ return FALSE;
+ }
+
+ LLKeyboardBinding bind;
+ bind.mKey = key;
+ bind.mMask = mask;
+ bind.mFunction = function;
+
+ mKeyBindings[mode].push_back(bind);
+
+ return TRUE;
+}
+
+BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name)
+{
+ S32 index;
+ typedef boost::function function_t;
+ function_t function = NULL;
+
+ function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+ if (result)
+ {
+ function = *result;
+ }
+
+ if (!function)
+ {
+ LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+ return FALSE;
+ }
+
+ // check for duplicate first and overwrite
+ S32 size = mMouseBindings[mode].size();
+ for (index = 0; index < size; index++)
+ {
+ if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
+ break;
+ }
+
+ if (mode >= MODE_COUNT)
+ {
+ LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
+ return FALSE;
+ }
+
+ LLMouseBinding bind;
+ bind.mMouse = mouse;
+ bind.mMask = mask;
+ bind.mFunction = function;
+
+ mMouseBindings[mode].push_back(bind);
+
+ return TRUE;
+}
+
+LLViewerInput::KeyBinding::KeyBinding()
+: key("key"),
+ mouse("mouse"),
+ mask("mask"),
+ command("command")
+{}
+
+LLViewerInput::KeyMode::KeyMode()
+: bindings("binding")
+{}
+
+LLViewerInput::Keys::Keys()
+: first_person("first_person"),
+ third_person("third_person"),
+ sitting("sitting"),
+ edit_avatar("edit_avatar")
+{}
+
+void LLViewerInput::resetBindings()
+{
+ for (S32 i = 0; i < MODE_COUNT; i++)
+ {
+ mKeyBindings[i].clear();
+ mMouseBindings[i].clear();
+ }
+}
+
+S32 LLViewerInput::loadBindingsXML(const std::string& filename)
+{
+ resetBindings();
+
+ S32 binding_count = 0;
+ Keys keys;
+ LLSimpleXUIParser parser;
+
+ if (parser.readXUI(filename, keys)
+ && keys.validateBlock())
+ {
+ binding_count += loadBindingMode(keys.first_person, MODE_FIRST_PERSON);
+ binding_count += loadBindingMode(keys.third_person, MODE_THIRD_PERSON);
+ binding_count += loadBindingMode(keys.sitting, MODE_SITTING);
+ binding_count += loadBindingMode(keys.edit_avatar, MODE_EDIT_AVATAR);
+ }
+ return binding_count;
+}
+
+S32 count_masks(const MASK &mask)
+{
+ S32 res = 0;
+ if (mask & MASK_CONTROL)
+ {
+ res++;
+ }
+ if (mask & MASK_SHIFT)
+ {
+ res++;
+ }
+ if (mask & MASK_ALT)
+ {
+ res++;
+ }
+ return res;
+}
+
+bool compare_key_by_mask(LLKeyboardBinding i1, LLKeyboardBinding i2)
+{
+ return (count_masks(i1.mMask) > count_masks(i2.mMask));
+}
+
+bool compare_mouse_by_mask(LLMouseBinding i1, LLMouseBinding i2)
+{
+ return (count_masks(i1.mMask) > count_masks(i2.mMask));
+}
+
+S32 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode)
+{
+ S32 binding_count = 0;
+ for (LLInitParam::ParamIterator::const_iterator it = keymode.bindings.begin(),
+ end_it = keymode.bindings.end();
+ it != end_it;
+ ++it)
+ {
+ bool processed = false;
+ std::string key_str = it->key.getValue();
+ if (!key_str.empty() && key_str != "NONE")
+ {
+ KEY key;
+ LLKeyboard::keyFromString(key_str, &key);
+ if (key != KEY_NONE)
+ {
+ MASK mask;
+ LLKeyboard::maskFromString(it->mask, &mask);
+ bindKey(mode, key, mask, it->command);
+ processed = true;
+ }
+ else
+ {
+ LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
+ }
+ }
+ if (!processed && it->mouse.isProvided() && !it->mouse.getValue().empty())
+ {
+ EMouseClickType mouse;
+ mouseFromString(it->mouse.getValue(), &mouse);
+ if (mouse != CLICK_NONE)
+ {
+ MASK mask;
+ LLKeyboard::maskFromString(it->mask, &mask);
+ bindMouse(mode, mouse, mask, it->command);
+ processed = true;
+ }
+ else
+ {
+ LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
+ }
+ }
+ if (processed)
+ {
+ // total
+ binding_count++;
+ }
+ }
+
+ // sort lists by mask (so that Shift+W is executed before W, if both are assigned, but if Shift+W is not assigned W should be executed)
+ std::sort(mKeyBindings[mode].begin(), mKeyBindings[mode].end(), compare_key_by_mask);
+ std::sort(mMouseBindings[mode].begin(), mMouseBindings[mode].end(), compare_mouse_by_mask);
+
+ return binding_count;
+}
+
+EKeyboardMode LLViewerInput::getMode() const
+{
+ if ( gAgentCamera.cameraMouselook() )
+ {
+ return MODE_FIRST_PERSON;
+ }
+ else if ( gMorphView && gMorphView->getVisible())
+ {
+ return MODE_EDIT_AVATAR;
+ }
+ else if (isAgentAvatarValid() && gAgentAvatarp->isSitting())
+ {
+ return MODE_SITTING;
+ }
+ else
+ {
+ return MODE_THIRD_PERSON;
+ }
+}
+
+bool LLViewerInput::scanKey(const std::vector &binding,
+ S32 binding_count,
+ KEY key,
+ MASK mask,
+ BOOL key_down,
+ BOOL key_up,
+ BOOL key_level,
+ bool repeat) const
+{
+ for (S32 i = 0; i < binding_count; i++)
+ {
+ if (binding[i].mKey == key)
+ {
+ if ((binding[i].mMask & mask) == binding[i].mMask)
+ {
+ bool res = false;
+ if (key_down && !repeat)
+ {
+ // ...key went down this frame, call function
+ res = binding[i].mFunction( KEYSTATE_DOWN );
+ return true;
+ }
+ else if (key_up)
+ {
+ // ...key went down this frame, call function
+ res = binding[i].mFunction( KEYSTATE_UP );
+ }
+ else if (key_level)
+ {
+ // ...key held down from previous frame
+ // Not windows, just call the function.
+ res = binding[i].mFunction( KEYSTATE_LEVEL );
+ }//if
+ // Key+Mask combinations are supposed to be unique, so we won't find anything else
+ return res;
+ }//if
+ }//if
+ }//for
+ return false;
+}
+
+// Called from scanKeyboard.
+bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
+{
+ if (LLApp::isExiting())
+ {
+ return false;
+ }
+
+ S32 mode = getMode();
+ // Consider keyboard scanning as NOT mouse event. JC
+ MASK mask = gKeyboard->currentMask(FALSE);
+
+ if (mKeyHandledByUI[key])
+ {
+ return false;
+ }
+
+ // don't process key down on repeated keys
+ BOOL repeat = gKeyboard->getKeyRepeated(key);
+
+ bool res = scanKey(mKeyBindings[mode], mKeyBindings[mode].size(), key, mask, key_down, key_up, key_level, repeat);
+
+ if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
+ {
+ if (key_down && !repeat)
+ {
+ res = agen_control_lbutton_handle(KEYSTATE_DOWN);
+ }
+ if (key_up)
+ {
+ res = agen_control_lbutton_handle(KEYSTATE_UP);
+ }
+ }
+ return res;
+}
+
+BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
+{
+ BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down);
+
+ if (clicktype != CLICK_NONE)
+ {
+ // Special case
+ // If UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set
+ // handle !down as if we are handling doubleclick
+
+ bool double_click_sp = (clicktype == CLICK_LEFT
+ && (mMouseLevel[CLICK_DOUBLELEFT] != MOUSE_STATE_SILENT)
+ && mMouseLevel[CLICK_LEFT] == MOUSE_STATE_SILENT);
+ if (double_click_sp && !down)
+ {
+ // Process doubleclick instead
+ clicktype = CLICK_DOUBLELEFT;
+ }
+
+
+ if (double_click_sp && down)
+ {
+ // Consume click.
+ // Due to handling, double click that is not handled will be immediately followed by LMB click
+ }
+ // If UI handled 'down', it should handle 'up' as well
+ // If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI
+ else if (handled)
+ {
+ // UI handled new 'down' so iterupt whatever state we were in.
+ if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
+ {
+ if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+ {
+ mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
+ }
+ else
+ {
+ mMouseLevel[clicktype] = MOUSE_STATE_UP;
+ }
+ }
+ }
+ else if (down)
+ {
+ if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+ {
+ // this is repeated hit (mouse does not repeat event until release)
+ // for now treat rapid clicking like mouse being held
+ mMouseLevel[clicktype] = MOUSE_STATE_LEVEL;
+ }
+ else
+ {
+ mMouseLevel[clicktype] = MOUSE_STATE_DOWN;
+ }
+ }
+ else if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
+ {
+ // Released mouse key
+ if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+ {
+ mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
+ }
+ else
+ {
+ mMouseLevel[clicktype] = MOUSE_STATE_UP;
+ }
+ }
+ }
+
+ return handled;
+}
+
+bool LLViewerInput::scanMouse(const std::vector &binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const
+{
+ for (S32 i = 0; i < binding_count; i++)
+ {
+ if (binding[i].mMouse == mouse && (binding[i].mMask & mask) == binding[i].mMask)
+ {
+ bool res = false;
+ switch (state)
+ {
+ case MOUSE_STATE_DOWN:
+ res = binding[i].mFunction(KEYSTATE_DOWN);
+ break;
+ case MOUSE_STATE_CLICK:
+ // Button went down and up in scope of single frame
+ // might not work best with some functions,
+ // but some function need specific states specifically
+ res = binding[i].mFunction(KEYSTATE_DOWN);
+ res |= binding[i].mFunction(KEYSTATE_UP);
+ break;
+ case MOUSE_STATE_LEVEL:
+ res = binding[i].mFunction(KEYSTATE_LEVEL);
+ break;
+ case MOUSE_STATE_UP:
+ res = binding[i].mFunction(KEYSTATE_UP);
+ break;
+ default:
+ break;
+ }
+ // Key+Mask combinations are supposed to be unique, no need to continue
+ return res;
+ }
+ }
+ return false;
+}
+
+// todo: this recods key, scanMouse() triggers functions with EKeystate
+bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const
+{
+ bool res = false;
+ S32 mode = getMode();
+ MASK mask = gKeyboard->currentMask(TRUE);
+ res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state);
+ // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
+ if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
+ {
+ switch (state)
+ {
+ case MOUSE_STATE_DOWN:
+ agen_control_lbutton_handle(KEYSTATE_DOWN);
+ res = true;
+ break;
+ case MOUSE_STATE_CLICK:
+ // might not work best with some functions,
+ // but some function need specific states too specifically
+ agen_control_lbutton_handle(KEYSTATE_DOWN);
+ agen_control_lbutton_handle(KEYSTATE_UP);
+ res = true;
+ break;
+ case MOUSE_STATE_UP:
+ agen_control_lbutton_handle(KEYSTATE_UP);
+ res = true;
+ break;
+ default:
+ break;
+ }
+ }
+ return res;
+}
+
+void LLViewerInput::scanMouse()
+{
+ for (S32 i = 0; i < CLICK_COUNT; i++)
+ {
+ if (mMouseLevel[i] != MOUSE_STATE_SILENT)
+ {
+ scanMouse((EMouseClickType)i, mMouseLevel[i]);
+ if (mMouseLevel[i] == MOUSE_STATE_DOWN)
+ {
+ // mouse doesn't support 'continued' state, so after handling, switch to LEVEL
+ mMouseLevel[i] = MOUSE_STATE_LEVEL;
+ }
+ else if (mMouseLevel[i] == MOUSE_STATE_UP || mMouseLevel[i] == MOUSE_STATE_CLICK)
+ {
+ mMouseLevel[i] = MOUSE_STATE_SILENT;
+ }
+ }
+ }
+}
+
+bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode)
+{
+ S32 size = mMouseBindings[mode].size();
+ for (S32 index = 0; index < size; index++)
+ {
+ if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
+ return true;
+ }
+ return false;
+}
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
new file mode 100644
index 0000000000..8461e0cd9b
--- /dev/null
+++ b/indra/newview/llviewerinput.h
@@ -0,0 +1,179 @@
+/**
+ * @file llviewerinput.h
+ * @brief LLViewerInput class header file
+ *
+ * $LicenseInfo:firstyear=2005&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_LLVIEWERINPUT_H
+#define LL_LLVIEWERINPUT_H
+
+#include "llkeyboard.h" // For EKeystate
+#include "llinitparam.h"
+
+const S32 MAX_KEY_BINDINGS = 128; // was 60
+
+class LLNamedFunction
+{
+public:
+ LLNamedFunction() : mFunction(NULL) { };
+ ~LLNamedFunction() { };
+
+ std::string mName;
+ LLKeyFunc mFunction;
+};
+
+class LLKeyboardBinding
+{
+public:
+ KEY mKey;
+ MASK mMask;
+
+ LLKeyFunc mFunction;
+};
+
+class LLMouseBinding
+{
+public:
+ EMouseClickType mMouse;
+ MASK mMask;
+
+ LLKeyFunc mFunction;
+};
+
+
+typedef enum e_keyboard_mode
+{
+ MODE_FIRST_PERSON,
+ MODE_THIRD_PERSON,
+ MODE_EDIT_AVATAR,
+ MODE_SITTING,
+ MODE_COUNT
+} EKeyboardMode;
+
+class LLWindow;
+
+void bind_keyboard_functions();
+
+class LLViewerInput
+{
+public:
+ struct KeyBinding : public LLInitParam::Block
+ {
+ Mandatory key,
+ mask,
+ command;
+ Optional mouse; // Note, not mandatory for the sake of backward campatibility with keys.xml
+
+ KeyBinding();
+ };
+
+ struct KeyMode : public LLInitParam::Block
+ {
+ Multiple bindings;
+
+ KeyMode();
+ };
+
+ struct Keys : public LLInitParam::Block
+ {
+ Optional first_person,
+ third_person,
+ sitting,
+ edit_avatar;
+
+ Keys();
+ };
+
+ LLViewerInput();
+
+ BOOL handleKey(KEY key, MASK mask, BOOL repeated);
+ BOOL handleKeyUp(KEY key, MASK mask);
+
+ S32 loadBindingsXML(const std::string& filename); // returns number bound, 0 on error
+ EKeyboardMode getMode() const;
+
+ static BOOL modeFromString(const std::string& string, S32 *mode); // False on failure
+ static BOOL mouseFromString(const std::string& string, EMouseClickType *mode);// False on failure
+
+ bool scanKey(KEY key,
+ BOOL key_down,
+ BOOL key_up,
+ BOOL key_level) const;
+
+ // handleMouse() records state, scanMouse() goes through states, scanMouse(click) processes individual saved states after UI is done with them
+ BOOL handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
+ void scanMouse();
+
+ bool isMouseBindUsed(const EMouseClickType mouse, const MASK mask = MASK_NONE, const S32 mode = MODE_THIRD_PERSON);
+
+private:
+ bool scanKey(const std::vector &binding,
+ S32 binding_count,
+ KEY key,
+ MASK mask,
+ BOOL key_down,
+ BOOL key_up,
+ BOOL key_level,
+ bool repeat) const;
+
+ enum EMouseState
+ {
+ MOUSE_STATE_DOWN, // key down this frame
+ MOUSE_STATE_CLICK, // key went up and down in scope of same frame
+ MOUSE_STATE_LEVEL, // clicked again fast, or never released
+ MOUSE_STATE_UP, // went up this frame
+ MOUSE_STATE_SILENT // notified about 'up', do not notify again
+ };
+ bool scanMouse(EMouseClickType click, EMouseState state) const;
+ bool scanMouse(const std::vector &binding,
+ S32 binding_count,
+ EMouseClickType mouse,
+ MASK mask,
+ EMouseState state) const;
+
+ S32 loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode);
+ BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name);
+ BOOL bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name);
+ void resetBindings();
+
+ // Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
+
+ // TODO: at some point it is better to remake this, especially keyaboard part
+ // would be much better to send to functions actual state of the button than
+ // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown)
+ std::vector mKeyBindings[MODE_COUNT];
+ std::vector mMouseBindings[MODE_COUNT];
+
+ typedef std::map key_remap_t;
+ key_remap_t mRemapKeys[MODE_COUNT];
+ std::set mKeysSkippedByUI;
+ BOOL mKeyHandledByUI[KEY_COUNT]; // key processed successfully by UI
+
+ // This is indentical to what llkeyboard does (mKeyRepeated, mKeyLevel, mKeyDown e t c),
+ // just instead of remembering individually as bools, we record state as enum
+ EMouseState mMouseLevel[CLICK_COUNT]; // records of key state
+};
+
+extern LLViewerInput gViewerInput;
+bool agent_push_forward(EKeystate s);// Mouse movement by Singularity
+#endif // LL_LLVIEWERINPUT_H
diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp
index d8bb7c1960..030f0b6cd2 100644
--- a/indra/newview/llviewerjoystick.cpp
+++ b/indra/newview/llviewerjoystick.cpp
@@ -1427,6 +1427,8 @@ bool LLViewerJoystick::isLikeSpaceNavigator() const
#if LIB_NDOF
return (isJoystickInitialized()
&& (strncmp(mNdofDev->product, "SpaceNavigator", 14) == 0
+ // FIRE-30846 - Add combined product string that is returned by some devices
+ || strncmp(mNdofDev->product, "3Dconnexion SpaceNavigator", 26) == 0
|| strncmp(mNdofDev->product, "SpaceExplorer", 13) == 0
|| strncmp(mNdofDev->product, "SpaceTraveler", 13) == 0
|| strncmp(mNdofDev->product, "SpacePilot", 10) == 0));
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
deleted file mode 100644
index f1f9f9e34e..0000000000
--- a/indra/newview/llviewerkeyboard.cpp
+++ /dev/null
@@ -1,1111 +0,0 @@
-/**
- * @file llviewerkeyboard.cpp
- * @brief LLViewerKeyboard class implementation
- *
- * $LicenseInfo:firstyear=2005&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 "llappviewer.h"
-#include "llfloaterreg.h"
-#include "llviewerkeyboard.h"
-#include "llmath.h"
-#include "llagent.h"
-#include "llagentcamera.h"
-// [FS Communication UI]
-// #include "llfloaterimnearbychat.h"
-#include "fsnearbychathub.h"
-#include "lllineeditor.h"
-// [FS Communication UI]
-#include "llviewercontrol.h"
-#include "llfocusmgr.h"
-#include "llmorphview.h"
-#include "llmoveview.h"
-#include "lltoolfocus.h"
-#include "llviewerwindow.h"
-#include "llvoavatarself.h"
-#include "llfloatercamera.h"
-#include "llinitparam.h"
-#include "llfloaterwebcontent.h"
-#include "fsfloatersearch.h"
-
-//
-// Constants
-//
-
-const F32 FLY_TIME = 0.5f;
-const F32 FLY_FRAMES = 4;
-
-const F32 NUDGE_TIME = 0.25f; // in seconds
-const S32 NUDGE_FRAMES = 2;
-const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed
-
-struct LLKeyboardActionRegistry
-: public LLRegistrySingleton, LLKeyboardActionRegistry>
-{
- LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
-};
-
-LLViewerKeyboard gViewerKeyboard;
-
-void agent_jump( EKeystate s )
-{
- static BOOL first_fly_attempt(TRUE);
- if (KEYSTATE_UP == s)
- {
- first_fly_attempt = TRUE;
- return;
- }
- F32 time = gKeyboard->getCurKeyElapsedTime();
- S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
-
- // Chalice Yao's crouch toggle
- if (gSavedPerAccountSettings.getBOOL("FSCrouchToggleStatus"))
- {
- gSavedPerAccountSettings.setBOOL("FSCrouchToggleStatus", FALSE);
- }
- //
-
- if( time < FLY_TIME
- || frame_count <= FLY_FRAMES
- || gAgent.upGrabbed()
- || !gSavedSettings.getBOOL("AutomaticFly"))
- {
- gAgent.moveUp(1);
- }
- else
- {
- gAgent.setFlying(TRUE, first_fly_attempt);
- first_fly_attempt = FALSE;
- gAgent.moveUp(1);
- }
-}
-
-void agent_push_down( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- // Chalice Yao's crouch toggle
- //gAgent.moveUp(-1);
- else if (KEYSTATE_DOWN == s && !gAgent.getFlying() && !gAgentAvatarp->isSitting() && gSavedPerAccountSettings.getBOOL("FSCrouchToggle"))
- {
- if (gSavedPerAccountSettings.getBOOL("FSCrouchToggleStatus"))
- {
- gSavedPerAccountSettings.setBOOL("FSCrouchToggleStatus", FALSE);
- }
- else
- {
- gSavedPerAccountSettings.setBOOL("FSCrouchToggleStatus", TRUE);
- gAgent.moveUp(-1);
- }
- }
- else
- {
- gAgent.moveUp(-1);
- }
- //
-}
-
-static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode)
-{
-// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
- if ( (gAgent.mDoubleTapRunMode == mode) && (gAgent.getTempRun()) )
- gAgent.clearTempRun();
-// [/RLVa:KB]
-// if (gAgent.mDoubleTapRunMode == mode &&
-// gAgent.getRunning() &&
-// !gAgent.getAlwaysRun())
-// {
-// // Turn off temporary running.
-// gAgent.clearRunning();
-// gAgent.sendWalkRun(gAgent.getRunning());
-// }
-}
-
-static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode)
-{
- if (KEYSTATE_UP == s)
- {
- // Note: in case shift is already released, slide left/right run
- // will be released in agent_turn_left()/agent_turn_right()
- agent_check_temporary_run(mode);
- }
- else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") &&
- KEYSTATE_DOWN == s &&
- !gAgent.getRunning())
- {
- if (gAgent.mDoubleTapRunMode == mode &&
- gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME)
- {
- // Same walk-key was pushed again quickly; this is a
- // double-tap so engage temporary running.
-// gAgent.setRunning();
-// gAgent.sendWalkRun(gAgent.getRunning());
-// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i
- gAgent.setTempRun();
-// [/RLVa:KB]
- }
-
- // Pressing any walk-key resets the double-tap timer
- gAgent.mDoubleTapRunTimer.reset();
- gAgent.mDoubleTapRunMode = mode;
- }
-}
-
-static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
-{
- agent_handle_doubletap_run(s, mode);
- if (KEYSTATE_UP == s) return;
-
- F32 time = gKeyboard->getCurKeyElapsedTime();
- S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
-
- if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
- {
- gAgent.moveAtNudge(direction);
- }
- else
- {
- gAgent.moveAt(direction);
- }
-}
-
-void camera_move_forward( EKeystate s );
-
-void agent_push_forward( EKeystate s )
-{
- if(gAgent.isMovementLocked()) return;
-
- //in free camera control mode we need to intercept keyboard events for avatar movements
- if (LLFloaterCamera::inFreeCameraMode())
- {
- camera_move_forward(s);
- }
- else
- {
- agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD);
- }
-}
-
-void camera_move_backward( EKeystate s );
-
-void agent_push_backward( EKeystate s )
-{
- if(gAgent.isMovementLocked()) return;
-
- //in free camera control mode we need to intercept keyboard events for avatar movements
- if (LLFloaterCamera::inFreeCameraMode())
- {
- camera_move_backward(s);
- }
- else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook"))
- {
- gAgentCamera.changeCameraToThirdPerson();
- }
- else
- {
- agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD);
- }
-}
-
-static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
-{
- agent_handle_doubletap_run(s, mode);
- if( KEYSTATE_UP == s ) return;
- F32 time = gKeyboard->getCurKeyElapsedTime();
- S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
-
- if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
- {
- gAgent.moveLeftNudge(direction);
- }
- else
- {
- gAgent.moveLeft(direction);
- }
-}
-
-
-void agent_slide_left( EKeystate s )
-{
- if(gAgent.isMovementLocked()) return;
- agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT);
-}
-
-
-void agent_slide_right( EKeystate s )
-{
- if(gAgent.isMovementLocked()) return;
- agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT);
-}
-
-void camera_spin_around_cw( EKeystate s );
-
-void agent_turn_left( EKeystate s )
-{
- //in free camera control mode we need to intercept keyboard events for avatar movements
- if (LLFloaterCamera::inFreeCameraMode())
- {
- camera_spin_around_cw(s);
- return;
- }
-
- if(gAgent.isMovementLocked()) return;
-
- if (LLToolCamera::getInstance()->mouseSteerMode())
- {
- agent_slide_left(s);
- }
- else
- {
- if (KEYSTATE_UP == s)
- {
- // Check temporary running. In case user released 'left' key with shift already released.
- agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT);
- return;
- }
- F32 time = gKeyboard->getCurKeyElapsedTime();
- gAgent.moveYaw( LLFloaterMove::getYawRate( time ) );
- }
-}
-
-void camera_spin_around_ccw( EKeystate s );
-
-void agent_turn_right( EKeystate s )
-{
- //in free camera control mode we need to intercept keyboard events for avatar movements
- if (LLFloaterCamera::inFreeCameraMode())
- {
- camera_spin_around_ccw(s);
- return;
- }
-
- if(gAgent.isMovementLocked()) return;
-
- if (LLToolCamera::getInstance()->mouseSteerMode())
- {
- agent_slide_right(s);
- }
- else
- {
- if (KEYSTATE_UP == s)
- {
- // Check temporary running. In case user released 'right' key with shift already released.
- agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT);
- return;
- }
- F32 time = gKeyboard->getCurKeyElapsedTime();
- gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) );
- }
-}
-
-void agent_look_up( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgent.movePitch(-1);
- //gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
-}
-
-
-void agent_look_down( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgent.movePitch(1);
- //gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
-}
-
-void agent_toggle_fly( EKeystate s )
-{
- // Only catch the edge
- if (KEYSTATE_DOWN == s )
- {
- LLAgent::toggleFlying();
- }
-}
-
-F32 get_orbit_rate()
-{
- F32 time = gKeyboard->getCurKeyElapsedTime();
- if( time < NUDGE_TIME )
- {
- F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
- //LL_INFOS() << rate << LL_ENDL;
- return rate;
- }
- else
- {
- return 1;
- }
-}
-
-void camera_spin_around_ccw( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
-}
-
-
-void camera_spin_around_cw( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitRightKey( get_orbit_rate() );
-}
-
-void camera_spin_around_ccw_sitting( EKeystate s )
-{
- if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return;
- if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
- {
- //send keystrokes, but do not change camera
- agent_turn_right(s);
- }
- else
- {
- //change camera but do not send keystrokes
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
- }
-}
-
-
-void camera_spin_around_cw_sitting( EKeystate s )
-{
- if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return;
- if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
- {
- //send keystrokes, but do not change camera
- agent_turn_left(s);
- }
- else
- {
- //change camera but do not send keystrokes
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitRightKey( get_orbit_rate() );
- }
-}
-
-
-void camera_spin_over( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitUpKey( get_orbit_rate() );
-}
-
-
-void camera_spin_under( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitDownKey( get_orbit_rate() );
-}
-
-void camera_spin_over_sitting( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled())
- {
- //send keystrokes, but do not change camera
- agent_jump(s);
- }
- else
- {
- //change camera but do not send keystrokes
- gAgentCamera.setOrbitUpKey( get_orbit_rate() );
- }
-}
-
-
-void camera_spin_under_sitting( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled())
- {
- //send keystrokes, but do not change camera
- agent_push_down(s);
- }
- else
- {
- //change camera but do not send keystrokes
- gAgentCamera.setOrbitDownKey( get_orbit_rate() );
- }
-}
-
-void camera_move_forward( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitInKey( get_orbit_rate() );
-}
-
-
-void camera_move_backward( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitOutKey( get_orbit_rate() );
-}
-
-void camera_move_forward_sitting( EKeystate s )
-{
- if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return;
- if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
- {
- agent_push_forward(s);
- }
- else
- {
- gAgentCamera.setOrbitInKey( get_orbit_rate() );
- }
-}
-
-
-void camera_move_backward_sitting( EKeystate s )
-{
- if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return;
-
- if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
- {
- agent_push_backward(s);
- }
- else
- {
- gAgentCamera.setOrbitOutKey( get_orbit_rate() );
- }
-}
-
-void camera_pan_up( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setPanUpKey( get_orbit_rate() );
-}
-
-void camera_pan_down( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setPanDownKey( get_orbit_rate() );
-}
-
-void camera_pan_left( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setPanLeftKey( get_orbit_rate() );
-}
-
-void camera_pan_right( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setPanRightKey( get_orbit_rate() );
-}
-
-void camera_pan_in( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setPanInKey( get_orbit_rate() );
-}
-
-void camera_pan_out( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setPanOutKey( get_orbit_rate() );
-}
-
-void camera_move_forward_fast( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitInKey(2.5f);
-}
-
-void camera_move_backward_fast( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gAgentCamera.unlockView();
- gAgentCamera.setOrbitOutKey(2.5f);
-}
-
-
-void edit_avatar_spin_ccw( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gMorphView->setCameraDrivenByKeys( TRUE );
- gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
- //gMorphView->orbitLeft( get_orbit_rate() );
-}
-
-
-void edit_avatar_spin_cw( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gMorphView->setCameraDrivenByKeys( TRUE );
- gAgentCamera.setOrbitRightKey( get_orbit_rate() );
- //gMorphView->orbitRight( get_orbit_rate() );
-}
-
-void edit_avatar_spin_over( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gMorphView->setCameraDrivenByKeys( TRUE );
- gAgentCamera.setOrbitUpKey( get_orbit_rate() );
- //gMorphView->orbitUp( get_orbit_rate() );
-}
-
-
-void edit_avatar_spin_under( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gMorphView->setCameraDrivenByKeys( TRUE );
- gAgentCamera.setOrbitDownKey( get_orbit_rate() );
- //gMorphView->orbitDown( get_orbit_rate() );
-}
-
-void edit_avatar_move_forward( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gMorphView->setCameraDrivenByKeys( TRUE );
- gAgentCamera.setOrbitInKey( get_orbit_rate() );
- //gMorphView->orbitIn();
-}
-
-
-void edit_avatar_move_backward( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- gMorphView->setCameraDrivenByKeys( TRUE );
- gAgentCamera.setOrbitOutKey( get_orbit_rate() );
- //gMorphView->orbitOut();
-}
-
-void stop_moving( EKeystate s )
-{
- if( KEYSTATE_UP == s ) return;
- // stop agent
- gAgent.setControlFlags(AGENT_CONTROL_STOP);
-
- // cancel autopilot
- gAgent.stopAutoPilot();
-}
-
-void start_chat( EKeystate s )
-{
- if (LLAppViewer::instance()->quitRequested())
- {
- return; // can't talk, gotta go, kthxbye!
- }
-
- // start chat
- // [FS Communication UI]
- //LLFloaterIMNearbyChat::startChat(NULL);
- FSNearbyChat::instance().showDefaultChatBar(TRUE);
- // [FS Communication UI]
-}
-
-void start_gesture( EKeystate s )
-{
- // If avatar is pointing at something, don't start gesture.
- // This works around the bug with Shared Media prims.
- if (gAgentCamera.mPointAtObject)
- {
- return;
- }
-
- // FIRE-4167: Don't start gesture if a floater with web content has focus
- LLFloater* focused_floater = gFloaterView->getFocusedFloater();
- if (focused_floater && (dynamic_cast(focused_floater) || dynamic_cast(focused_floater)))
- {
- return;
- }
-
- LLUICtrl* focus_ctrlp = dynamic_cast(gFocusMgr.getKeyboardFocus());
- if (KEYSTATE_UP == s &&
- ! (focus_ctrlp && focus_ctrlp->acceptsTextInput()))
- {
- // [FS Communication UI]
- //if ((LLFloaterReg::getTypedInstance("nearby_chat"))->getCurrentChat().empty())
- //{
- // // No existing chat in chat editor, insert '/'
- // LLFloaterIMNearbyChat::startChat("/");
- //}
- //else
- //{
- // // Don't overwrite existing text in chat editor
- // LLFloaterIMNearbyChat::startChat(NULL);
- //}
-
- FSNearbyChat::instance().showDefaultChatBar(TRUE, "/");
- // [FS Communication UI]
- }
-}
-
-#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
-REGISTER_KEYBOARD_ACTION("jump", agent_jump);
-REGISTER_KEYBOARD_ACTION("push_down", agent_push_down);
-REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
-REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward);
-REGISTER_KEYBOARD_ACTION("look_up", agent_look_up);
-REGISTER_KEYBOARD_ACTION("look_down", agent_look_down);
-REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly);
-REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left);
-REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right);
-REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left);
-REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right);
-REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw);
-REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw);
-REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
-REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting);
-REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over);
-REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under);
-REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting);
-REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting);
-REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward);
-REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward);
-REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting);
-REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting);
-REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up);
-REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down);
-REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left);
-REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right);
-REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in);
-REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out);
-REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast);
-REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under);
-REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward);
-REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward);
-REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving);
-REGISTER_KEYBOARD_ACTION("start_chat", start_chat);
-REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture);
-#undef REGISTER_KEYBOARD_ACTION
-
-LLViewerKeyboard::LLViewerKeyboard()
-{
- for (S32 i = 0; i < MODE_COUNT; i++)
- {
- mBindingCount[i] = 0;
- }
-
- for (S32 i = 0; i < KEY_COUNT; i++)
- {
- mKeyHandledByUI[i] = FALSE;
- }
- // we want the UI to never see these keys so that they can always control the avatar/camera
- for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++)
- {
- mKeysSkippedByUI.insert(k);
- }
-}
-
-BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)
-{
- if (string == "FIRST_PERSON")
- {
- *mode = MODE_FIRST_PERSON;
- return TRUE;
- }
- else if (string == "THIRD_PERSON")
- {
- *mode = MODE_THIRD_PERSON;
- return TRUE;
- }
- else if (string == "EDIT")
- {
- *mode = MODE_EDIT;
- return TRUE;
- }
- else if (string == "EDIT_AVATAR")
- {
- *mode = MODE_EDIT_AVATAR;
- return TRUE;
- }
- else if (string == "SITTING")
- {
- *mode = MODE_SITTING;
- return TRUE;
- }
- else
- {
- *mode = MODE_THIRD_PERSON;
- return FALSE;
- }
-}
-
-BOOL LLViewerKeyboard::handleKey(KEY translated_key, MASK translated_mask, BOOL repeated)
-{
- // check for re-map
- EKeyboardMode mode = gViewerKeyboard.getMode();
- U32 keyidx = (translated_mask<<16) | translated_key;
- key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx);
- if (iter != mRemapKeys[mode].end())
- {
- translated_key = (iter->second) & 0xff;
- translated_mask = (iter->second)>>16;
- }
-
- // No repeats of F-keys
- BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12);
- if (!repeatable_key && repeated)
- {
- return FALSE;
- }
-
- LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL;
- // skip skipped keys
- if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end())
- {
- mKeyHandledByUI[translated_key] = FALSE;
- //LL_INFOS("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL;
- LL_INFOS_ONCE("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL; // Change log message to not print out every time
- }
- else
- {
- // it is sufficient to set this value once per call to handlekey
- // without clearing it, as it is only used in the subsequent call to scanKey
- mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask);
- // mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress)
- // NOT whether some UI shortcut wishes to handle the keypress
-
- }
- return mKeyHandledByUI[translated_key];
-}
-
-BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)
-{
- return gViewerWindow->handleKeyUp(translated_key, translated_mask);
-}
-
-BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
-{
- S32 index;
- typedef boost::function function_t;
- function_t function = NULL;
- std::string name;
-
- // Allow remapping of F2-F12
- if (function_name[0] == 'F')
- {
- int c1 = function_name[1] - '0';
- int c2 = function_name[2] ? function_name[2] - '0' : -1;
- if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9)
- {
- int idx = c1;
- if (c2 >= 0)
- idx = idx*10 + c2;
- if (idx >=2 && idx <= 12)
- {
- U32 keyidx = ((mask<<16)|key);
- (mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1)));
- return TRUE;
- }
- }
- }
-
- // Not remapped, look for a function
-
- function_t* result = LLKeyboardActionRegistry::getValue(function_name);
- if (result)
- {
- function = *result;
- }
-
- if (!function)
- {
- LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
- return FALSE;
- }
-
- // check for duplicate first and overwrite
- for (index = 0; index < mBindingCount[mode]; index++)
- {
- if (key == mBindings[mode][index].mKey && mask == mBindings[mode][index].mMask)
- break;
- }
-
- if (index >= MAX_KEY_BINDINGS)
- {
- LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
- return FALSE;
- }
-
- if (mode >= MODE_COUNT)
- {
- LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
- return FALSE;
- }
-
- mBindings[mode][index].mKey = key;
- mBindings[mode][index].mMask = mask;
- mBindings[mode][index].mFunction = function;
-
- if (index == mBindingCount[mode])
- mBindingCount[mode]++;
-
- return TRUE;
-}
-
-LLViewerKeyboard::KeyBinding::KeyBinding()
-: key("key"),
- mask("mask"),
- command("command")
-{}
-
-LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode)
-: bindings("binding"),
- mode(_mode)
-{}
-
-LLViewerKeyboard::Keys::Keys()
-: first_person("first_person", KeyMode(MODE_FIRST_PERSON)),
- third_person("third_person", KeyMode(MODE_THIRD_PERSON)),
- edit("edit", KeyMode(MODE_EDIT)),
- sitting("sitting", KeyMode(MODE_SITTING)),
- edit_avatar("edit_avatar", KeyMode(MODE_EDIT_AVATAR))
-{}
-
-S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
-{
- // Allow instant change of keyboard layout
- for (S32 i = 0; i < MODE_COUNT; i++)
- {
- mBindingCount[i] = 0;
-
- for (S32 j = 0; j < MAX_KEY_BINDINGS; j++)
- {
- mBindings[i][j] = LLKeyBinding();
- }
- }
- //
-
- S32 binding_count = 0;
- Keys keys;
- LLSimpleXUIParser parser;
-
- if (parser.readXUI(filename, keys)
- && keys.validateBlock())
- {
- binding_count += loadBindingMode(keys.first_person);
- binding_count += loadBindingMode(keys.third_person);
- binding_count += loadBindingMode(keys.edit);
- binding_count += loadBindingMode(keys.sitting);
- binding_count += loadBindingMode(keys.edit_avatar);
- }
- return binding_count;
-}
-
-S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode)
-{
- S32 binding_count = 0;
- for (LLInitParam::ParamIterator::const_iterator it = keymode.bindings.begin(),
- end_it = keymode.bindings.end();
- it != end_it;
- ++it)
- {
- KEY key;
- MASK mask;
- LLKeyboard::keyFromString(it->key, &key);
- LLKeyboard::maskFromString(it->mask, &mask);
- bindKey(keymode.mode, key, mask, it->command);
- binding_count++;
- }
-
- return binding_count;
-}
-
-S32 LLViewerKeyboard::loadBindings(const std::string& filename)
-{
- LLFILE *fp;
- const S32 BUFFER_SIZE = 2048;
- char buffer[BUFFER_SIZE]; /* Flawfinder: ignore */
- // *NOTE: This buffer size is hard coded into scanf() below.
- char mode_string[MAX_STRING] = ""; /* Flawfinder: ignore */
- char key_string[MAX_STRING] = ""; /* Flawfinder: ignore */
- char mask_string[MAX_STRING] = ""; /* Flawfinder: ignore */
- char function_string[MAX_STRING] = ""; /* Flawfinder: ignore */
- S32 mode = MODE_THIRD_PERSON;
- KEY key = 0;
- MASK mask = 0;
- S32 tokens_read;
- S32 binding_count = 0;
- S32 line_count = 0;
-
- if(filename.empty())
- {
- LL_ERRS() << " No filename specified" << LL_ENDL;
- return 0;
- }
-
- fp = LLFile::fopen(filename, "r");
-
- if (!fp)
- {
- return 0;
- }
-
-
- while (!feof(fp))
- {
- line_count++;
- if (!fgets(buffer, BUFFER_SIZE, fp))
- break;
-
- // skip over comments, blank lines
- if (buffer[0] == '#' || buffer[0] == '\n') continue;
-
- // grab the binding strings
- tokens_read = sscanf( /* Flawfinder: ignore */
- buffer,
- "%254s %254s %254s %254s",
- mode_string,
- key_string,
- mask_string,
- function_string);
-
- if (tokens_read == EOF)
- {
- LL_INFOS() << "Unexpected end-of-file at line " << line_count << " of key binding file " << filename << LL_ENDL;
- fclose(fp);
- return 0;
- }
- else if (tokens_read < 4)
- {
- LL_INFOS() << "Can't read line " << line_count << " of key binding file " << filename << LL_ENDL;
- continue;
- }
-
- // convert mode
- if (!modeFromString(mode_string, &mode))
- {
- LL_INFOS() << "Unknown mode on line " << line_count << " of key binding file " << filename << LL_ENDL;
- LL_INFOS() << "Mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR" << LL_ENDL;
- continue;
- }
-
- // convert key
- if (!LLKeyboard::keyFromString(key_string, &key))
- {
- LL_INFOS() << "Can't interpret key on line " << line_count << " of key binding file " << filename << LL_ENDL;
- continue;
- }
-
- // convert mask
- if (!LLKeyboard::maskFromString(mask_string, &mask))
- {
- LL_INFOS() << "Can't interpret mask on line " << line_count << " of key binding file " << filename << LL_ENDL;
- continue;
- }
-
- // bind key
- if (bindKey(mode, key, mask, function_string))
- {
- binding_count++;
- }
- }
-
- fclose(fp);
-
- return binding_count;
-}
-
-
-EKeyboardMode LLViewerKeyboard::getMode()
-{
- if ( gAgentCamera.cameraMouselook() )
- {
- return MODE_FIRST_PERSON;
- }
- else if ( gMorphView && gMorphView->getVisible())
- {
- return MODE_EDIT_AVATAR;
- }
- else if (isAgentAvatarValid() && gAgentAvatarp->isSitting())
- {
- return MODE_SITTING;
- }
- else
- {
- return MODE_THIRD_PERSON;
- }
-}
-
-
-// Called from scanKeyboard.
-void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
-{
- if (LLApp::isExiting())
- {
- return;
- }
-
- S32 mode = getMode();
- // Consider keyboard scanning as NOT mouse event. JC
- MASK mask = gKeyboard->currentMask(FALSE);
-
- LLKeyBinding* binding = mBindings[mode];
- S32 binding_count = mBindingCount[mode];
-
-
- if (mKeyHandledByUI[key])
- {
- return;
- }
-
- // don't process key down on repeated keys
- BOOL repeat = gKeyboard->getKeyRepeated(key);
-
- for (S32 i = 0; i < binding_count; i++)
- {
- //for (S32 key = 0; key < KEY_COUNT; key++)
- if (binding[i].mKey == key)
- {
- //if (binding[i].mKey == key && binding[i].mMask == mask)
- if (binding[i].mMask == mask)
- {
- if (key_down && !repeat)
- {
- // ...key went down this frame, call function
- binding[i].mFunction( KEYSTATE_DOWN );
- }
- else if (key_up)
- {
- // ...key went down this frame, call function
- binding[i].mFunction( KEYSTATE_UP );
- }
- else if (key_level)
- {
- // ...key held down from previous frame
- // Not windows, just call the function.
- binding[i].mFunction( KEYSTATE_LEVEL );
- }//if
- }//if
- }//for
- }//for
-}
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
deleted file mode 100644
index 80f326175f..0000000000
--- a/indra/newview/llviewerkeyboard.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * @file llviewerkeyboard.h
- * @brief LLViewerKeyboard class header file
- *
- * $LicenseInfo:firstyear=2005&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_LLVIEWERKEYBOARD_H
-#define LL_LLVIEWERKEYBOARD_H
-
-#include "llkeyboard.h" // For EKeystate
-#include "llinitparam.h"
-
-const S32 MAX_NAMED_FUNCTIONS = 100;
-const S32 MAX_KEY_BINDINGS = 128; // was 60
-
-class LLNamedFunction
-{
-public:
- LLNamedFunction() : mFunction(NULL) { };
- ~LLNamedFunction() { };
-
- std::string mName;
- LLKeyFunc mFunction;
-};
-
-typedef enum e_keyboard_mode
-{
- MODE_FIRST_PERSON,
- MODE_THIRD_PERSON,
- MODE_EDIT,
- MODE_EDIT_AVATAR,
- MODE_SITTING,
- MODE_COUNT
-} EKeyboardMode;
-
-
-void bind_keyboard_functions();
-
-class LLViewerKeyboard
-{
-public:
- struct KeyBinding : public LLInitParam::Block
- {
- Mandatory key,
- mask,
- command;
-
- KeyBinding();
- };
-
- struct KeyMode : public LLInitParam::Block
- {
- Multiple bindings;
- EKeyboardMode mode;
- KeyMode(EKeyboardMode mode);
- };
-
- struct Keys : public LLInitParam::Block
- {
- Optional first_person,
- third_person,
- edit,
- sitting,
- edit_avatar;
-
- Keys();
- };
-
- LLViewerKeyboard();
-
- BOOL handleKey(KEY key, MASK mask, BOOL repeated);
- BOOL handleKeyUp(KEY key, MASK mask);
-
- S32 loadBindings(const std::string& filename); // returns number bound, 0 on error
- S32 loadBindingsXML(const std::string& filename); // returns number bound, 0 on error
- EKeyboardMode getMode();
-
- BOOL modeFromString(const std::string& string, S32 *mode); // False on failure
-
- void scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level);
-
-private:
- S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode);
- BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name);
-
- // Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
- S32 mBindingCount[MODE_COUNT];
- LLKeyBinding mBindings[MODE_COUNT][MAX_KEY_BINDINGS];
-
- typedef std::map key_remap_t;
- key_remap_t mRemapKeys[MODE_COUNT];
- std::set mKeysSkippedByUI;
- BOOL mKeyHandledByUI[KEY_COUNT]; // key processed successfully by UI
-};
-
-extern LLViewerKeyboard gViewerKeyboard;
-void agent_push_forward(EKeystate s);// Mouse movement by Singularity
-#endif // LL_LLVIEWERKEYBOARD_H
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index fd777ad8ff..77376b74e8 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -5822,6 +5822,20 @@ void handle_take_copy()
derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);
}
+void handle_link_objects()
+{
+ // We don't use a shortcut for two completely different functions based on context
+ //if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ //{
+ // LLFloaterReg::toggleInstanceOrBringToFront("places");
+ //}
+ //else
+ //
+ {
+ LLSelectMgr::getInstance()->linkObjects();
+ }
+}
+
// You can return an object to its owner if it is on your land.
class LLObjectReturn : public view_listener_t
{
@@ -9475,6 +9489,20 @@ class LLAdvancedToggleDoubleClickTeleport: public view_listener_t
}
};
+// Add telemetry controls to the viewer menus
+class FSTelemetryToggleActive : public view_listener_t
+{
+protected:
+
+ bool handleEvent(const LLSD& userdata)
+ {
+ BOOL checked = gSavedSettings.getBOOL( "FSTelemetryActive" );
+ gSavedSettings.setBOOL( "FSTelemetryActive", !checked );
+ FSTelemetry::active = !checked;
+ return true;
+ }
+};
+//
void menu_toggle_attached_lights(void* user_data)
{
LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
@@ -10266,7 +10294,6 @@ BOOL LLViewerMenuHolderGL::hideMenus()
if (LLMenuHolderGL::hideMenus())
{
- LLToolPie::instance().blockClickToWalk();
handled = TRUE;
}
@@ -11616,7 +11643,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY");
view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid");
view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart");
- commit.add("Tools.Link", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
+ commit.add("Tools.Link", boost::bind(&handle_link_objects));
commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations");
view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys");
@@ -11831,6 +11858,9 @@ void initialize_menus()
//Develop (clear cache immediately)
commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) );
+ // Add telemetry controls to the viewer Develop menu (Toggle profiling)
+ view_listener_t::addMenu(new FSTelemetryToggleActive(), "Develop.ToggleTelemetry");
+
// Admin >Object
view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy");
view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf");
diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h
index e378c2448a..3bed65e1c4 100644
--- a/indra/newview/llviewerprecompiledheaders.h
+++ b/indra/newview/llviewerprecompiledheaders.h
@@ -106,5 +106,31 @@
// Library includes from llmessage project
#include "llcachename.h"
+// Firestorm additions
+#include "llavatarname.h"
+#include "llavatarnamecache.h"
+#include "llcorehttputil.h"
+#include "llformat.h"
+#include "llmatrix4a.h"
+#include "llvector4a.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
#endif
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 751df0582d..608c95f222 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -45,7 +45,8 @@
#include "llmeshrepository.h"
#include "llnotificationhandler.h"
#include "llpanellogin.h"
-#include "llviewerkeyboard.h"
+#include "llsetkeybinddialog.h"
+#include "llviewerinput.h"
#include "llviewermenu.h"
// physics display changes
#include "llspatialpartition.h"
@@ -180,7 +181,7 @@
#include "llviewergesture.h"
#include "llviewertexturelist.h"
#include "llviewerinventory.h"
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
#include "llviewermedia.h"
#include "llviewermediafocus.h"
#include "llviewermenu.h"
@@ -1021,7 +1022,18 @@ LLViewerWindow::Params::Params()
{}
-BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
+void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask)
+{
+ if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
+ {
+ // If the current tool didn't process the click, we should show
+ // the pie menu. This can be done by passing the event to the pie
+ // menu tool.
+ LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
+ }
+}
+
+BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
{
const char* buttonname = "";
const char* buttonstatestr = "";
@@ -1045,28 +1057,30 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK
switch (clicktype)
{
- case LLMouseHandler::CLICK_LEFT:
+ case CLICK_LEFT:
mLeftMouseDown = down;
buttonname = "Left";
break;
- case LLMouseHandler::CLICK_RIGHT:
+ case CLICK_RIGHT:
mRightMouseDown = down;
buttonname = "Right";
break;
- case LLMouseHandler::CLICK_MIDDLE:
+ case CLICK_MIDDLE:
mMiddleMouseDown = down;
buttonname = "Middle";
break;
- case LLMouseHandler::CLICK_DOUBLELEFT:
+ case CLICK_DOUBLELEFT:
mLeftMouseDown = down;
buttonname = "Left Double Click";
break;
- case LLMouseHandler::CLICK_BUTTON4:
+ case CLICK_BUTTON4:
buttonname = "Button 4";
break;
- case LLMouseHandler::CLICK_BUTTON5:
+ case CLICK_BUTTON5:
buttonname = "Button 5";
break;
+ default:
+ break; // COUNT and NONE
}
LLView::sMouseHandlerMessage.clear();
@@ -1117,6 +1131,11 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK
LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname));
}
+ else if (down && clicktype == CLICK_RIGHT)
+ {
+ handlePieMenu(x, y, mask);
+ r = TRUE;
+ }
return r;
}
@@ -1163,7 +1182,12 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK
return TRUE;
}
-
+ if (down && clicktype == CLICK_RIGHT)
+ {
+ handlePieMenu(x, y, mask);
+ return TRUE;
+ }
+
// If we got this far on a down-click, it wasn't handled.
// Up-clicks, though, are always handled as far as the OS is concerned.
BOOL default_rtn = !down;
@@ -1182,7 +1206,8 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask
mMouseDownTimer.reset();
}
BOOL down = TRUE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
+ //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick
+ return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
}
BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask)
@@ -1190,8 +1215,7 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK ma
// try handling as a double-click first, then a single-click if that
// wasn't handled.
BOOL down = TRUE;
- if (handleAnyMouseClick(window, pos, mask,
- LLMouseHandler::CLICK_DOUBLELEFT, down))
+ if (gViewerInput.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down))
{
return TRUE;
}
@@ -1205,47 +1229,24 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
mMouseDownTimer.stop();
}
BOOL down = FALSE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
+ return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
}
-
-
BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
{
- S32 x = pos.mX;
- S32 y = pos.mY;
- x = ll_round((F32)x / mDisplayScale.mV[VX]);
- y = ll_round((F32)y / mDisplayScale.mV[VY]);
-
BOOL down = TRUE;
- BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
- if (handle)
- return handle;
-
- // *HACK: this should be rolled into the composite tool logic, not
- // hardcoded at the top level.
- if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
- {
- // If the current tool didn't process the click, we should show
- // the pie menu. This can be done by passing the event to the pie
- // menu tool.
- LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
- // show_context_menu( x, y, mask );
- }
-
- return TRUE;
+ return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
}
BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
{
BOOL down = FALSE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
+ return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
}
BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
{
BOOL down = TRUE;
- LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_MIDDLE, true);
- handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
+ gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
// Always handled as far as the OS is concerned.
return TRUE;
@@ -1400,8 +1401,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
{
BOOL down = FALSE;
- LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_MIDDLE, false);
- handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
+ gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
// Always handled as far as the OS is concerned.
return TRUE;
@@ -1412,12 +1412,10 @@ BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask
switch (button)
{
case 4:
- LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_BUTTON4, down);
- handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_BUTTON4, down);
+ gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON4, down);
break;
case 5:
- LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_BUTTON5, down);
- handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_BUTTON5, down);
+ gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON5, down);
break;
default:
break;
@@ -1564,9 +1562,6 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)
BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
{
- // Let the voice chat code check for its PTT key. Note that this never affects event processing.
- LLVoiceClient::getInstance()->keyDown(key, mask);
-
if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
{
gAgent.clearAFK();
@@ -1585,14 +1580,12 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
return FALSE;
}
- return gViewerKeyboard.handleKey(key, mask, repeated);
+ // remaps, handles ignored cases and returns back to viewer window.
+ return gViewerInput.handleKey(key, mask, repeated);
}
BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
{
- // Let the voice chat code check for its PTT key. Note that this never affects event processing.
- LLVoiceClient::getInstance()->keyUp(key, mask);
-
// Let the inspect tool code check for ALT key to set LLToolSelectRect active instead LLToolCamera
LLToolCompInspect * tool_inspectp = LLToolCompInspect::getInstance();
if (LLToolMgr::getInstance()->getCurrentTool() == tool_inspectp)
@@ -1600,13 +1593,13 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
tool_inspectp->keyUp(key, mask);
}
- return gViewerKeyboard.handleKeyUp(key, mask);
+ return gViewerInput.handleKeyUp(key, mask);
}
void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
{
LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
- gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
+ gViewerInput.scanKey(key, key_down, key_up, key_level);
return; // Be clear this function returns nothing
}
@@ -3119,6 +3112,13 @@ void LLViewerWindow::setTitle(const std::string& win_title)
// Takes a single keyup event, usually when UI is visible
BOOL LLViewerWindow::handleKeyUp(KEY key, MASK mask)
{
+ if (LLSetKeyBindDialog::recordKey(key, mask, FALSE))
+ {
+ LL_DEBUGS() << "KeyUp handled by LLSetKeyBindDialog" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key, mask);
+ return TRUE;
+ }
+
LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
if (keyboard_focus
@@ -3162,23 +3162,74 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
// hide tooltips on keypress
LLToolTipMgr::instance().blockToolTips();
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+ // Menus get handled on key down instead of key up
+ // so keybindings have to be recorded before that
+ if (LLSetKeyBindDialog::recordKey(key, mask, TRUE))
+ {
+ LL_DEBUGS() << "Key handled by LLSetKeyBindDialog" << LL_ENDL;
+ LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+ return TRUE;
+ }
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+
if (keyboard_focus
- && !(mask & (MASK_CONTROL | MASK_ALT))
- && !gFocusMgr.getKeystrokesOnly())
- {
- // We have keyboard focus, and it's not an accelerator
- if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
+ && !gFocusMgr.getKeystrokesOnly())
+ {
+#ifdef LL_WINDOWS
+ // On windows Alt Gr key generates additional Ctrl event, as result handling situations
+ // like 'AltGr + D' will result in 'Alt+Ctrl+D'. If it results in WM_CHAR, don't let it
+ // pass into menu or it will trigger 'develop' menu assigned to this combination on top
+ // of character handling.
+ // Alt Gr can be additionally modified by Shift
+ const MASK alt_gr = MASK_CONTROL | MASK_ALT;
+ if ((mask & alt_gr) != 0
+ && key >= 0x30
+ && key <= 0x5A
+ && (GetKeyState(VK_RMENU) & 0x8000) != 0
+ && (GetKeyState(VK_RCONTROL) & 0x8000) == 0) // ensure right control is not pressed, only left one
{
- return keyboard_focus->handleKey(key, mask, FALSE );
+ // Alt Gr key is represented as right alt and left control.
+ // Any alt+ctrl combination is treated as Alt Gr by TranslateMessage() and
+ // will generate a WM_CHAR message, but here we only treat virtual Alt Graph
+ // key by checking if this specific combination has unicode char.
+ //
+ // I decided to handle only virtual RAlt+LCtrl==AltGr combination to minimize
+ // impact on menu, but the right way might be to handle all Alt+Ctrl calls.
+
+ BYTE keyboard_state[256];
+ if (GetKeyboardState(keyboard_state))
+ {
+ const int char_count = 6;
+ wchar_t chars[char_count];
+ HKL layout = GetKeyboardLayout(0);
+ // ToUnicodeEx changes buffer state on OS below Win10, which is undesirable,
+ // but since we already did a TranslateMessage() in gatherInput(), this
+ // should have no negative effect
+ int res = ToUnicodeEx(key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout);
+ if (res == 1 && chars[0] >= 0x20)
+ {
+ // Let it fall through to character handler and get a WM_CHAR.
+ return TRUE;
+ }
+ }
}
- else if (key < 0x80)
- {
- // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
- return (keyboard_focus != NULL);
- }
- }
+#endif
+
+ if (!(mask & (MASK_CONTROL | MASK_ALT)))
+ {
+ // We have keyboard focus, and it's not an accelerator
+ if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
+ {
+ return keyboard_focus->handleKey(key, mask, FALSE);
+ }
+ else if (key < 0x80)
+ {
+ // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
+ return TRUE;
+ }
+ }
+ }
// let menus handle navigation keys for navigation
if ((gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE))
@@ -3434,7 +3485,8 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
{
if (mask != MASK_ALT)
{
- return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
+ // remaps, handles ignored cases and returns back to viewer window.
+ return gViewerInput.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
}
}
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index d040980b62..b5e0ed73bb 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -176,8 +176,9 @@ public:
void initWorldUI();
void setUIVisibility(bool);
bool getUIVisibility();
+ void handlePieMenu(S32 x, S32 y, MASK mask);
- BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down);
+ BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
//
// LLWindowCallback interface implementation
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 5b707fa36f..637212cddd 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -217,8 +217,6 @@ const LLVoiceVersionInfo LLVoiceClient::getVersion()
void LLVoiceClient::updateSettings()
{
setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
- std::string keyString = gSavedSettings.getString("PushToTalkButton");
- setPTTKey(keyString);
setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic");
@@ -660,32 +658,6 @@ bool LLVoiceClient::getPTTIsToggle()
return mPTTIsToggle;
}
-void LLVoiceClient::setPTTKey(std::string &key)
-{
- // Value is stored as text for readability
- if(key == "MiddleMouse")
- {
- mPTTMouseButton = LLMouseHandler::CLICK_MIDDLE;
- }
- else if(key == "MouseButton4")
- {
- mPTTMouseButton = LLMouseHandler::CLICK_BUTTON4;
- }
- else if (key == "MouseButton5")
- {
- mPTTMouseButton = LLMouseHandler::CLICK_BUTTON5;
- }
- else
- {
- mPTTMouseButton = 0;
- if(!LLKeyboard::keyFromString(key, &mPTTKey))
- {
- // If the call failed, don't match any key.
- key = KEY_NONE;
- }
- }
-}
-
void LLVoiceClient::inputUserControlState(bool down)
{
if(mPTTIsToggle)
@@ -706,43 +678,6 @@ void LLVoiceClient::toggleUserPTTState(void)
setUserPTTState(!getUserPTTState());
}
-void LLVoiceClient::keyDown(KEY key, MASK mask)
-{
- if (gKeyboard->getKeyRepeated(key))
- {
- // ignore auto-repeat keys
- return;
- }
-
- if (mPTTMouseButton == 0 && LLAgent::isActionAllowed("speak") && (key == mPTTKey))
- {
- bool down = gKeyboard->getKeyDown(mPTTKey);
- if (down)
- {
- inputUserControlState(down);
- }
- }
-
-}
-void LLVoiceClient::keyUp(KEY key, MASK mask)
-{
- if (mPTTMouseButton == 0 && (key == mPTTKey))
- {
- bool down = gKeyboard->getKeyDown(mPTTKey);
- if (!down)
- {
- inputUserControlState(down);
- }
- }
-}
-void LLVoiceClient::updateMouseState(S32 click, bool down)
-{
- if(mPTTMouseButton == click && LLAgent::isActionAllowed("speak"))
- {
- inputUserControlState(down);
- }
-}
-
//-------------------------------------------
// nearby speaker accessors
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 6f0add2288..b3147e2e06 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -437,16 +437,10 @@ public:
void setUsePTT(bool usePTT);
void setPTTIsToggle(bool PTTIsToggle);
bool getPTTIsToggle();
- void setPTTKey(std::string &key);
-
+
void updateMicMuteLogic();
-
+
BOOL lipSyncEnabled();
-
- // PTT key triggering
- void keyDown(KEY key, MASK mask);
- void keyUp(KEY key, MASK mask);
- void updateMouseState(S32 click, bool down);
boost::signals2::connection MicroChangedCallback(const micro_changed_signal_t::slot_type& cb ) { return mMicroChangedSignal.connect(cb); }
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 3167f7cce5..d848810eeb 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -6349,9 +6349,10 @@ static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh");
void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
{
llassert(group);
+ LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);// move out one scope (but are these even useful as dupes?)
if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY))
{
- LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);
+ // LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB);// move out one scope (but are these even useful as dupes?)
LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers
group->mBuilt = 1.f;
diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp
index 9e4297baaf..aa8c79b0d2 100644
--- a/indra/newview/llwindowlistener.cpp
+++ b/indra/newview/llwindowlistener.cpp
@@ -37,7 +37,7 @@
#include "llview.h"
#include "llviewinject.h"
#include "llviewerwindow.h"
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
#include "llrootview.h"
#include "llsdutil.h"
#include "stringize.h"
@@ -279,7 +279,7 @@ void LLWindowListener::keyDown(LLSD const & evt)
response.setResponse(target_view->getInfo());
gFocusMgr.setKeyboardFocus(target_view);
- gViewerKeyboard.handleKey(key, mask, false);
+ gViewerInput.handleKey(key, mask, false);
if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
}
else
@@ -291,7 +291,7 @@ void LLWindowListener::keyDown(LLSD const & evt)
}
else
{
- gViewerKeyboard.handleKey(key, mask, false);
+ gViewerInput.handleKey(key, mask, false);
if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
}
}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 6b9f27a101..0a5e59418d 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -4753,7 +4753,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
{
LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
- LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
+ // LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY); remove duplicate zone scope
LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS);
diff --git a/indra/newview/skins/default/xui/de/control_table_contents_camera.xml b/indra/newview/skins/default/xui/de/control_table_contents_camera.xml
new file mode 100644
index 0000000000..984a6aa87e
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/control_table_contents_camera.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/de/control_table_contents_columns_basic.xml b/indra/newview/skins/default/xui/de/control_table_contents_columns_basic.xml
new file mode 100644
index 0000000000..8f6e96e4ad
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/control_table_contents_columns_basic.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/de/control_table_contents_editing.xml b/indra/newview/skins/default/xui/de/control_table_contents_editing.xml
new file mode 100644
index 0000000000..726a27611e
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/control_table_contents_editing.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/de/control_table_contents_media.xml b/indra/newview/skins/default/xui/de/control_table_contents_media.xml
new file mode 100644
index 0000000000..c594aea187
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/control_table_contents_media.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/de/control_table_contents_movement.xml b/indra/newview/skins/default/xui/de/control_table_contents_movement.xml
new file mode 100644
index 0000000000..ea8ab77e5c
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/control_table_contents_movement.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/de/floater_preferences.xml b/indra/newview/skins/default/xui/de/floater_preferences.xml
index 7765814df1..322a19e023 100644
--- a/indra/newview/skins/default/xui/de/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/de/floater_preferences.xml
@@ -20,6 +20,7 @@ https://accounts.secondlife.com/change_email/?lang=de-DE
+
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index 48bcf1f4a4..ef047c2355 100644
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -16,6 +16,7 @@
+
+
-
+
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml
index a969fcbd9c..e9ac21e01e 100644
--- a/indra/newview/skins/default/xui/fr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml
@@ -116,10 +116,16 @@
+
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml
index e168aeb94a..08c5ea67f0 100644
--- a/indra/newview/skins/default/xui/fr/panel_login.xml
+++ b/indra/newview/skins/default/xui/fr/panel_login.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php?lang=fr
- https://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/fr/panel_login_first.xml b/indra/newview/skins/default/xui/fr/panel_login_first.xml
index 8f40d0230c..7db6ac7bf6 100644
--- a/indra/newview/skins/default/xui/fr/panel_login_first.xml
+++ b/indra/newview/skins/default/xui/fr/panel_login_first.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php?lang=fr
- https://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_UI.xml b/indra/newview/skins/default/xui/fr/panel_preferences_UI.xml
index e3c7a61b41..db08c38422 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_UI.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_UI.xml
@@ -51,9 +51,10 @@
(Redémarrage requis)
-
-
+
(Redémarrage requis)
+
+
@@ -70,6 +71,18 @@
+ Format heure :
+
+
+
+
+
+
+
+
+
+
+
Barres de Navigation & de Favoris :
@@ -81,6 +94,7 @@
+
Utiliser des fenêtres distinctes pour :
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_firestorm.xml b/indra/newview/skins/default/xui/fr/panel_preferences_firestorm.xml
index fc921c4c21..dba0daf029 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_firestorm.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_firestorm.xml
@@ -22,6 +22,8 @@
+
+
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml
index 7d5db3f508..c57734a419 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_graphics1.xml
@@ -125,6 +125,7 @@
+
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_move.xml b/indra/newview/skins/default/xui/fr/panel_preferences_move.xml
index af9f8946b2..9f9ea3eae8 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_move.xml
@@ -40,13 +40,13 @@
-
+
Prévision de mouvement si changement de région :
@@ -66,6 +66,7 @@
+
@@ -76,6 +77,7 @@
+
Options de la Minicarte :
diff --git a/indra/newview/skins/default/xui/fr/panel_region_environment.xml b/indra/newview/skins/default/xui/fr/panel_region_environment.xml
index 4b1d463b91..21949f9733 100644
--- a/indra/newview/skins/default/xui/fr/panel_region_environment.xml
+++ b/indra/newview/skins/default/xui/fr/panel_region_environment.xml
@@ -49,7 +49,7 @@
-
+
diff --git a/indra/newview/skins/default/xui/fr/panel_tools_texture.xml b/indra/newview/skins/default/xui/fr/panel_tools_texture.xml
index d028336ac7..56c04a0337 100644
--- a/indra/newview/skins/default/xui/fr/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/fr/panel_tools_texture.xml
@@ -109,4 +109,6 @@
+
+
diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml
index 39a35ff473..7dedaef05e 100644
--- a/indra/newview/skins/default/xui/fr/strings.xml
+++ b/indra/newview/skins/default/xui/fr/strings.xml
@@ -173,7 +173,7 @@ Version serveur vocal : [VOICE_VERSION]
Quitter
- http://join.secondlife.com/?sourceid=[sourceid]
+ https://www.firestormviewer.org/join-secondlife/
Grille principale de Second Life (Agni)
@@ -6041,4 +6041,531 @@ correctement. Si vous continuez à recevoir ce message d'erreur, veuillez v
[https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Base de connaissances]
+
+ Aucune vue de la caméra n'a encore été enregistrée.
+
+
+ Impossible de restaurer la vue de la caméra parce que la position de la caméra est au-delà de la distance d'affichage.
+
+
+ En raison des modifications apportées au code, il n'est plus nécessaire d'utiliser ce geste. Le réglage progressif de la distance d'affichage a été activé..
+
+
+ Position de la caméra [POS] copiée dans le presse-papiers.
+
+
+ Distance d'affichage réglèe [DISTANCE]m.
+
+
+ Résultat total pour [DICE]d[FACES][MODIFIER]: [RESULT].
+
+
+ Vous devez fournir des valeurs positives pour les dés (max 100) et les faces (max 1000).
+
+
+ Si vous souhaitez utiliser un modificateur, vous devez fournir un numéro de modificateur valide et le type de modificateur. Le modificateur doit être compris entre -1000 et 1000. Les types de modificateurs valides sont "+" (bonus), "-" (pénalités), ">", "<" (succès), "r>", "r<", "r" (relancer), "!p>", "!p<", "!p" (pénétrations), "!>", "!<" and "!" (explosions). Vous ne pouvez utiliser qu'un seul type de modificateur par tirage. Exemples : "[COMMAND] 1 20 + 5", "[COMMAND] 5 40 > 15", "[COMMAND] 10 25 ! 25", "[COMMAND] 15 25 !< 10".
+
+
+ Explosé
+
+
+ Pénétré
+
+
+ Succès
+
+
+ Relancer
+
+
+ Cette opération ne peut être réalisée car le viewer se figerait dans une boucle infinie. Veuillez modifier les critères.
+
+
+ '[RAND]' n'est pas une expression valable pour RAND(min,max). MAX doit être supérieur à MIN, les deux dans une fourchette de -10000 à 10000.
+
+
+ Bande passante maximale réglée à [VALUE] KBPS.
+
+
+ Téléportation proposée à [NAME].
+
+
+
+
+ avec support de Havok
+
+
+ avec support de OpenSimulator
+
+
+
+
+ '[TEXT]' introuvable
+
+
+ Aucun résultat
+
+
+ Recherche en cours...
+
+
+ Toutes catégories
+
+
+ Certains termes de votre requête de recherche ont été exclus en raison de restrictions de contenu, comme précisé dans les Community Standards.
+
+
+ Vos termes de recherche étant trop courts, aucune recherche n'a été effectuée.
+
+
+ La recherche à l'ancienne a été désactivée dans cette région.
+
+
+ Basse (1/7)
+
+
+ Moyenne-Basse (2/7)
+
+
+ Moyenne (3/7)
+
+
+ Moyenne-Élevée (4/7)
+
+
+ Élevée (5/7)
+
+
+ Élevée-Ultra (6/7)
+
+
+ Ultra (7/7)
+
+
+ Inconnu, au-delà de la normale, vérifiez le paramètre de débogage RenderQualityPerformance
+
+
+ [APP_NAME] ne peut pas créer le bridge LSL si "Activer le Bridge LSL" est désactivé dans les Préférences.
+
+
+ [APP_NAME] n'a pas pu créer un bridge LSL. Veuillez activer votre bibliothèque et vous reconnecter.
+
+
+ Création d'un bridge en cours, impossible d'en lancer un autre. Veuillez attendre quelques minutes avant de réessayer.
+
+
+ Création du bridge. Cela peut prendre un moment, veuillez patienter.
+
+
+ Bridge non créé. Le script de bridge n'a pas pu être créé.
+
+
+ Bridge non créé. Le bridge porte un nom incorrect. Veuillez utiliser le menu 'Moi/Santé de l'avatar/Recréer le Bridge' LSL de [APP_NAME] pour recréer le bridge.
+
+
+ Bridge non créé. Le bridge n'a pas pu être trouvé dans l'inventaire. Veuillez utiliser le menu 'Moi/Santé de l'avatar/Recréer le Bridge' LSL de [APP_NAME] pour recréer le bridge.
+
+
+ Le bridge n'a pas réussi à s'attacher. Il ne s'agit pas de la version actuelle du bridge. Veuillez utiliser le menu 'Moi/Santé de l'avatar/Recréer le Bridge' LSL de [APP_NAME] pour recréer le bridge.
+
+
+ Le bridge ne s'est pas attaché. Le bridge n'a pas été trouvé dans le bon emplacement de l'inventaire. Veuillez utiliser le menu 'Moi/Santé de l'avatar/Recréer le Bridge' LSL de [APP_NAME] pour recréer le bridge.
+
+
+ Le bridge ne s'est pas attaché. Quelque chose d'autre utilisait le point d'attache du bridge. Veuillez utiliser le menu 'Moi/Santé de l'avatar/Recréer le Bridge' LSL de [APP_NAME] pour recréer le bridge.
+
+
+ L'objet bridge n'a pas pu être trouvé. Impossible de procéder à sa création, fin de tâche.
+
+
+ L'inventaire du bridge contient des éléments inattendus.
+
+
+ Le bridge n'a pas fini de se créer, vous devrez peut-être utiliser la fonction 'Moi/Santé de l'avatar/Recréer le Bridge' LSL de [APP_NAME] pour le recréer avant de l'utiliser.
+
+
+ Bridge détaché.
+
+
+ Bridge créé.
+
+
+ Infos sur le script : '[OBJECT_NAME]': [[OBJECT_RUNNING_SCRIPT_COUNT]/[OBJECT_TOTAL_SCRIPT_COUNT]] scripts en cours d'exécution, [OBJECT_SCRIPT_MEMORY] KB taille limite de mémoire autorisée, [OBJECT_SCRIPT_TIME] ms de temps CPU utilisé.[PATHFINDING_TEXT]
+
+
+ Temps moyen d'utilisation du CPU pour la navigation avec recherche de chemin : [OBJECT_CHARACTER_TIME] ms.
+
+
+ID de l'objet : [INSPECTING_KEY]
+Description: [OBJECT_DESC]
+Prim racine : [OBJECT_ROOT]
+Prim count: [OBJECT_PRIM_COUNT]
+Impact sur le terrain : [OBJECT_PRIM_EQUIVALENCE]
+Articles de l'inventaire : [OBJECT_TOTAL_INVENTORY_COUNT]
+Vélocité : [OBJECT_VELOCITY]
+Position: [OBJECT_POS]
+Rotation: [OBJECT_ROT]
+Vitesse angulaire : [OBJECT_OMEGA] (radians per second)
+Créateur : [OBJECT_CREATOR]
+Propriétaire : [OBJECT_OWNER]
+Propriétaire précédent : [OBJECT_LAST_OWNER_ID]
+Posé par : [OBJECT_REZZER_KEY]
+Groupe : [OBJECT_GROUP]
+Date de création : [OBJECT_CREATION_TIME]
+Type de cheminement : [OBJECT_PATHFINDING_TYPE]
+Point d'attache : [OBJECT_ATTACHED_POINT]
+Attaché temporairement : [OBJECT_TEMP_ATTACHED]
+Votre position actuelle : [AVATAR_POS]
+
+
+ Info script : L'objet à vérifier n'est pas valable ou est hors de portée.
+
+
+ Info script : Réception d'une réponse malformée du bridge. Réessayez.
+
+
+ NOTICE : Un ou plusieurs scripts ont été ajoutés au bridge de votre [APP_NAME] ! Si vous ne vous attendiez pas à recevoir ce message, utilisez le menu Moi/Santé de l'avatar/Recréer le bridge LSL de [APP_NAME] pour recréer le bridge.
+
+
+ NOTICE : Le script du Bridge utilise l'ancien LSO (Limite de mémoire de 16 Ko) au lieu de la nouvelle machine virtuelle Mono (Limite de mémoire de 64 Ko), qui crée une forte probabilité de collision entre piles et de défaillance du bridge par manque de mémoire. Utilisez le menu Moi/Santé de l'avatar/Recréer le bridge LSL de [APP_NAME] pour recréer le bridge. Si vous voyez ce message à nouveau - veuillez essayer à nouveau dans une autre région.
+
+
+
+
+ [APP_NAME] Animation Overrider enabled.
+
+
+ [APP_NAME] Animation Overrider disabled.
+
+
+ Pause par un attachement scripté.
+
+
+ Relancé par un attachement scripté.
+
+
+ Animations de position debout mises en pause par un attachement scripté.
+
+
+ Animations de position debout relancées par un attachement scripté.
+
+
+
+
+ Distance d'affichage
+
+
+ Particules max.
+
+
+ LOD de l'avatar
+
+
+ Facteur de LOD
+
+
+ Avatars max.
+
+
+ Décalage des étiquettes
+
+
+ Étiquettes de nom
+
+
+ Cible du LookAt
+
+
+ Couleur sous le curseur
+
+
+
+
+ Pose T
+
+
+ Bras baissés, jambes jointes
+
+
+ Bras baissés, assis
+
+
+ Bras en bas, jambes jointes
+
+
+ Bras en bas, jambes écartées
+
+
+ Bras vers l'avant, jambes écartées
+
+
+ Bras vers l'avant, jambes jointes
+
+
+ Bras tendus, jambes écartées
+
+
+ Bras tendus, assis
+
+
+ Bras vers le haut, jambes écartées
+
+
+ Bras vers le haut, jambes serrées
+
+
+
+ Environnement partagé
+
+
+ Basé sur le cycle du jour
+
+
+ Rien
+
+
+
+ Mute de la discussion de groupe de [NAME].
+
+
+ Vous avez été invité à une conférence (ad-hoc) par [AVATAR_NAME], mais la visionneuse l'a automatiquement ignoré à cause de vos réglages.
+
+
+
+
+ L'appareil photo ne peut pas faire la mise au point sur l'utilisateur [AVATARNAME] parce qu'il est en dehors de votre distance d'affichage.
+
+
+ est entré dans la distance d'affichage ([DISTANCE] m).
+
+
+ a quitté la distance d'affichage.
+
+
+ est entré portée de discussion ([DISTANCE] m).
+
+
+ est hors de portée de discussion.
+
+
+ est entré dans la région.
+
+
+ est entré dans la région ([DISTANCE] m).
+
+
+ a quitté la région.
+
+
+ a déclenché l'alerte sur l'âge. Âge: [AGE] jour(s)
+
+
+
+ Le nombre total de scripts dans la région est passé de [OLD_VALUE] à [NEW_VALUE] ([DIFFERENCE]).
+
+
+ Le nombre total de scripts dans la région est passé de [OLD_VALUE] à [NEW_VALUE] ([DIFFERENCE]).
+
+
+ Le basculement du préprocesseur ne prendra effet que lorsque vous fermerez et rouvrirez cet éditeur.
+
+
+
+
+
+ Démarrage du préprocesseur de [APP_NAME]...
+
+
+ Avertissement : Préprocesseur non supporté dans cette version. ([WHERE])
+
+
+ Préprocesseur de [APP_NAME] désactivé par la directive à la ligne [LINENUMBER].
+
+
+ Réglages :
+
+
+ [ERR_NAME] ([LINENUMBER]): [ERR_DESC]
+
+
+ [SEVERITY]: [ERR_NAME] ([LINENUMBER]): [ERR_DESC]
+
+
+ [ERR_NAME] ([LINENUMBER]): exception captée: [ERR_DESC]
+
+
+ [ERR_NAME] ([LINENUMBER]): exception inattendue captée.
+
+
+ Détection de la directive compile-as-LSL2 outrepassant les préférences.
+
+
+ Détection de la directive compile-as-Mono outrepassant les préférences.
+
+
+
+
+ L'affichage de votre position actuelle dans la barre de menu a été désactivé par défaut pour la série de skin Starlight.
+
+
+ L'affichage de la barre de navigation a été activé par défaut pour la série de skin Starlight.
+
+
+
+
+ [SECONDS] plus tôt
+
+
+ Toujours en cours
+
+
+ inconnu
+
+
+
+ est en ligne.
+
+
+ est hors ligne.
+
+
+
+ Nouveau
+
+
+ Agent inconnu
+
+
+ Vous faites partie de [COUNT] groups ([REMAINING] restant).
+
+
+ Vous faites partie de [COUNT] groupes.
+
+
+ Code d'erreur SL : Format de message non valide. Réessayer plus tard.
+
+
+ Code d'erreur SL : La requête a expiré.
+
+
+ Code d'erreur SL : [STATUS] ( https://en.wikipedia.org/wiki/List_of_HTTP_status_codes ).
+
+
+ Téléportation par double clic activée.
+
+
+ Téléportation par double clic désactivée.
+
+
+ Toujours courir activé.
+
+
+ Toujours courir désactivé.
+
+
+ La région où vous êtes est sur le point de redémarrer. Si vous restez, vous serez déconnecté.
+
+
+ '[NAME]' a été ajouté à la liste de blocage.
+
+
+ '[NAME]' a été supprimé de la liste de blocage.
+
+
+ Je demande des informations sur la configuration de votre système.
+
+
+ Je demande des informations sur la configuration de votre système pour la raison suivante : [REASON]
+
+
+ Informations envoyées : [DATA]
+
+
+ Demande refusée.
+
+
+ La raison invoquée est la suivante : [REASON]
+
+
+
+
+ Tous les éléments
+
+
+ Eléments récents
+
+
+ Eléments portés
+
+
+
+ Un membre du groupe nommé [NAME]
+
+
+ (en ligne)
+
+
+
+ Normalement
+
+
+ Jamais
+
+
+ Entièrement
+
+
+
+ Complexité : [COMPLEXITY]
+
+
+ Surface de la texture : [TEXTURE_AREA] m²
+
+
+
+ Police inconnue
+
+
+ Mode inconnu
+
+
+ Texte
+
+
+ Envoi...
+[ASSET_NAME]
+
+
+ Oui
+
+
+ Non
+
+
+ Porter le dossier de l'inventaire
+
+
+ Image pour le vêtement
+
+
+ (Script inconnu)
+
+
+ [COST] L$
+
+
+
+ Importation des réglages Windlights...
+
+
+
+
+ Aucun élément
+
+
+ 1 élément
+
+
+ [NUM_ELEMENTS] éléments
+
diff --git a/indra/newview/skins/default/xui/it/panel_login.xml b/indra/newview/skins/default/xui/it/panel_login.xml
index 7a5ed68fac..47c20e1950 100644
--- a/indra/newview/skins/default/xui/it/panel_login.xml
+++ b/indra/newview/skins/default/xui/it/panel_login.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php?lang=it
- http://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/it/panel_login_first.xml b/indra/newview/skins/default/xui/it/panel_login_first.xml
index 5b04fd411a..cb3d7c656e 100644
--- a/indra/newview/skins/default/xui/it/panel_login_first.xml
+++ b/indra/newview/skins/default/xui/it/panel_login_first.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php?lang=it
- http://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_move.xml b/indra/newview/skins/default/xui/it/panel_preferences_move.xml
index 3103223900..481f732f3c 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_move.xml
@@ -46,7 +46,6 @@
-
diff --git a/indra/newview/skins/default/xui/ja/panel_login.xml b/indra/newview/skins/default/xui/ja/panel_login.xml
index 86e7e9dac4..07b12881d9 100644
--- a/indra/newview/skins/default/xui/ja/panel_login.xml
+++ b/indra/newview/skins/default/xui/ja/panel_login.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php?lang=ja
- https://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/ja/panel_login_first.xml b/indra/newview/skins/default/xui/ja/panel_login_first.xml
index 644cee25f2..a910a7e7bf 100644
--- a/indra/newview/skins/default/xui/ja/panel_login_first.xml
+++ b/indra/newview/skins/default/xui/ja/panel_login_first.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php?lang=ja
- https://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_move.xml b/indra/newview/skins/default/xui/ja/panel_preferences_move.xml
index fc764c5174..f949de0a23 100644
--- a/indra/newview/skins/default/xui/ja/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/ja/panel_preferences_move.xml
@@ -56,7 +56,6 @@
-
diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml
index 95ac48f0ac..7ffc21e60d 100644
--- a/indra/newview/skins/default/xui/ja/strings.xml
+++ b/indra/newview/skins/default/xui/ja/strings.xml
@@ -134,7 +134,7 @@
終了
- http://join.secondlife.com/index.php?lang=ja-JP&sourceid=[sourceid]
+ https://www.firestormviewer.org/join-secondlife/
https://www.firestormviewer.org/choose-your-platform/
diff --git a/indra/newview/skins/default/xui/pl/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/pl/floater_texture_ctrl.xml
index dfa7925037..c25cf80e07 100644
--- a/indra/newview/skins/default/xui/pl/floater_texture_ctrl.xml
+++ b/indra/newview/skins/default/xui/pl/floater_texture_ctrl.xml
@@ -12,7 +12,7 @@
-
+
Rozmiar:
@@ -31,7 +31,7 @@
-
+
diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml
index 1e8c1e6d4c..523af5fc4f 100644
--- a/indra/newview/skins/default/xui/pl/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml
@@ -402,6 +402,10 @@
+
+
+
+
diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml
index d73789e4f0..8ea6d93b2e 100644
--- a/indra/newview/skins/default/xui/pl/notifications.xml
+++ b/indra/newview/skins/default/xui/pl/notifications.xml
@@ -1387,7 +1387,7 @@ Możesz normalnie używać [APP_NAME], inni użytkownicy będą Cię widzieli po
Instalacja [APP_NAME] zakończona.
Jeżeli używasz [CURRENT_GRID] po raz pierwszy to musisz stworzyć konto żeby móc się zalogować.
-Czy chcesz przejść na stronę [http://join.secondlife.com secondlife.com] żeby stworzyć nowe konto?
+Czy chcesz przejść na stronę [https://www.firestormviewer.org/join-secondlife/ firestormviewer.org] żeby stworzyć nowe konto?
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/pl/panel_preferences_alerts.xml
index 95b7f69ae6..77e246fd64 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_alerts.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_alerts.xml
@@ -45,12 +45,14 @@
-
- Zawsze pokazuj:
-
-
- Nigdy nie pokazuj:
+
+ Ostrzeżenia przeglądarki, które można pokazać lub ukryć:
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_move.xml b/indra/newview/skins/default/xui/pl/panel_preferences_move.xml
index bd36be7da7..c9a03cad2f 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_move.xml
@@ -45,7 +45,6 @@
-
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index 56f61724fc..2526577265 100644
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -1383,7 +1383,7 @@ Enquando isso, use o [CURRENT_GRID] normalmente. Seu visual será exibido corret
A instalação do [APP_NAME] está pronta.
Se você ainda não conhece o [CURRENT_GRID], basta criar uma conta para começar.
-Voltar para [http://join.secondlife.com secondlife.com] para criar sua conta?
+Voltar para [https://www.firestormviewer.org/join-secondlife/ firestormviewer.org] para criar sua conta?
diff --git a/indra/newview/skins/default/xui/pt/panel_login.xml b/indra/newview/skins/default/xui/pt/panel_login.xml
index ffe637b3c1..b1e8bae513 100644
--- a/indra/newview/skins/default/xui/pt/panel_login.xml
+++ b/indra/newview/skins/default/xui/pt/panel_login.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php?lang=pt
- https://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/pt/panel_login_first.xml b/indra/newview/skins/default/xui/pt/panel_login_first.xml
index 86c61163bc..8b2ef04f95 100644
--- a/indra/newview/skins/default/xui/pt/panel_login_first.xml
+++ b/indra/newview/skins/default/xui/pt/panel_login_first.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php?lang=pt
- https://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml
index 10ae9fad15..758c723712 100644
--- a/indra/newview/skins/default/xui/pt/strings.xml
+++ b/indra/newview/skins/default/xui/pt/strings.xml
@@ -176,7 +176,7 @@ Versão do servidor de voz: [VOICE_VERSION]
Sair
- http://join.secondlife.com/?sourceid=[sourceid]
+ https://www.firestormviewer.org/join-secondlife/
http://secondlife.com/download
diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml
index 1e725f28ad..87e3202e01 100644
--- a/indra/newview/skins/default/xui/ru/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml
@@ -443,6 +443,10 @@
+
+
+
+
diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/ru/panel_preferences_alerts.xml
index 60614cc91b..6731aa5556 100644
--- a/indra/newview/skins/default/xui/ru/panel_preferences_alerts.xml
+++ b/indra/newview/skins/default/xui/ru/panel_preferences_alerts.xml
@@ -45,12 +45,14 @@
-
- Всегда показывать:
-
-
- Никогда не показывать:
+
+ Оповещения которые можно показать или скрыть:
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_move.xml b/indra/newview/skins/default/xui/ru/panel_preferences_move.xml
index 898fc525d2..7175fe5bfa 100644
--- a/indra/newview/skins/default/xui/ru/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/ru/panel_preferences_move.xml
@@ -45,7 +45,6 @@
-
diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml
index b66ec18c51..afadbd7788 100644
--- a/indra/newview/skins/default/xui/ru/strings.xml
+++ b/indra/newview/skins/default/xui/ru/strings.xml
@@ -225,7 +225,7 @@ SLURL: <nolink>[SLURL]</nolink>
Выйти
- http://join.secondlife.com/?sourceid=[sourceid]
+ https://www.firestormviewer.org/join-secondlife/
Second Life Главная Сетка (Agni)
diff --git a/indra/newview/skins/default/xui/tr/panel_login.xml b/indra/newview/skins/default/xui/tr/panel_login.xml
index e9fec9783f..d21bf3ba38 100644
--- a/indra/newview/skins/default/xui/tr/panel_login.xml
+++ b/indra/newview/skins/default/xui/tr/panel_login.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php
- https://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/tr/panel_login_first.xml b/indra/newview/skins/default/xui/tr/panel_login_first.xml
index 1fc80c2b97..46dc8e8414 100644
--- a/indra/newview/skins/default/xui/tr/panel_login_first.xml
+++ b/indra/newview/skins/default/xui/tr/panel_login_first.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php
- https://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml
index 571e7335ac..d50dd1893b 100644
--- a/indra/newview/skins/default/xui/tr/strings.xml
+++ b/indra/newview/skins/default/xui/tr/strings.xml
@@ -188,7 +188,7 @@ Ses Sunucusu Sürümü: [VOICE_VERSION]
Çık
- http://join.secondlife.com/?sourceid=[sourceid]
+ https://www.firestormviewer.org/join-secondlife/
Second Life Ana Ağı (Agni)
diff --git a/indra/newview/skins/default/xui/zh/panel_login.xml b/indra/newview/skins/default/xui/zh/panel_login.xml
index 59618972af..70c06b14bc 100644
--- a/indra/newview/skins/default/xui/zh/panel_login.xml
+++ b/indra/newview/skins/default/xui/zh/panel_login.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php
- https://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/zh/panel_login_first.xml b/indra/newview/skins/default/xui/zh/panel_login_first.xml
index 4d72fcdd03..1f7990e506 100644
--- a/indra/newview/skins/default/xui/zh/panel_login_first.xml
+++ b/indra/newview/skins/default/xui/zh/panel_login_first.xml
@@ -4,7 +4,7 @@
http://secondlife.com/account/request.php
- http://join.secondlife.com/
+ https://www.firestormviewer.org/join-secondlife/
diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml
index 8532adb490..a78afb2d2a 100644
--- a/indra/newview/skins/default/xui/zh/strings.xml
+++ b/indra/newview/skins/default/xui/zh/strings.xml
@@ -187,7 +187,7 @@ J2C 解碼器版本: [J2C_VERSION]
結束退出
- http://join.secondlife.com/?sourceid=[sourceid]
+ https://www.firestormviewer.org/join-secondlife/
http://secondlife.com/download
diff --git a/indra/newview/skins/firestorm/themes/dark/textures/textures.xml b/indra/newview/skins/firestorm/themes/dark/textures/textures.xml
new file mode 100644
index 0000000000..a01e155692
--- /dev/null
+++ b/indra/newview/skins/firestorm/themes/dark/textures/textures.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/indra/newview/skins/starlightcui/xui/de/floater_preferences.xml b/indra/newview/skins/starlightcui/xui/de/floater_preferences.xml
index 98a5ae06ab..203c047267 100644
--- a/indra/newview/skins/starlightcui/xui/de/floater_preferences.xml
+++ b/indra/newview/skins/starlightcui/xui/de/floater_preferences.xml
@@ -21,6 +21,7 @@ https://accounts.secondlife.com/change_email/?lang=de-DE
+
diff --git a/indra/newview/skins/starlightcui/xui/en/floater_preferences.xml b/indra/newview/skins/starlightcui/xui/en/floater_preferences.xml
index 4bcb36ef8a..89bad3ddbd 100644
--- a/indra/newview/skins/starlightcui/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/starlightcui/xui/en/floater_preferences.xml
@@ -153,6 +153,13 @@ https://accounts.secondlife.com/change_email/
layout="topleft"
help_topic="preferences_move_tab"
name="move" />
+
+
+
+
+ height="370">
+
+
+
+
+
+
+
+
diff --git a/indra/newview/skins/vintage/xui/pl/panel_people.xml b/indra/newview/skins/vintage/xui/pl/panel_people.xml
index 108ef0f203..690a84462e 100644
--- a/indra/newview/skins/vintage/xui/pl/panel_people.xml
+++ b/indra/newview/skins/vintage/xui/pl/panel_people.xml
@@ -38,35 +38,41 @@ Chcesz spotkać ludzi? Spróbuj użyć [secondlife:///app/worldmap Mapy Świata]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/newview/skins/vintage/xui/ru/panel_people.xml b/indra/newview/skins/vintage/xui/ru/panel_people.xml
index f591b48ca7..4b6e575b8e 100644
--- a/indra/newview/skins/vintage/xui/ru/panel_people.xml
+++ b/indra/newview/skins/vintage/xui/ru/panel_people.xml
@@ -37,41 +37,46 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/indra/tools/vstool/VSTool.csproj b/indra/tools/vstool/VSTool.csproj
old mode 100755
new mode 100644
diff --git a/indra/tools/vstool/VSTool.exe b/indra/tools/vstool/VSTool.exe
old mode 100755
new mode 100644
diff --git a/indra/tools/vstool/VSTool.sln b/indra/tools/vstool/VSTool.sln
old mode 100755
new mode 100644
diff --git a/indra/tools/vstool/main.cs b/indra/tools/vstool/main.cs
old mode 100755
new mode 100644
diff --git a/scripts/configure_firestorm.sh b/scripts/configure_firestorm.sh
index 1f18503aca..4ba88357f3 100755
--- a/scripts/configure_firestorm.sh
+++ b/scripts/configure_firestorm.sh
@@ -39,6 +39,7 @@ WANTS_SINGLEGRID=$FALSE
WANTS_AVX=$FALSE
WANTS_AVX2=$FALSE
WANTS_TESTBUILD=$FALSE
+WANTS_TRACY=$FALSE
WANTS_BUILD=$FALSE
WANTS_CRASHREPORTING=$FALSE
TARGET_PLATFORM="darwin" # darwin, windows, linux
@@ -77,6 +78,7 @@ showUsage()
echo " --singlegrid : Build for single grid usage (Requires --opensim)"
echo " --avx : Build with Advanced Vector Extensions"
echo " --avx2 : Build with Advanced Vector Extensions 2"
+ echo " --tracy : Build with Tracy Profiler support"
echo " --crashreporting : Build with crash reporting enabled"
echo " --testbuild : Create time-limited test build (build date + )"
echo " --platform : Build for specified platform (darwin | windows | linux)"
@@ -92,7 +94,7 @@ getArgs()
# $* = the options passed in from main
{
if [ $# -gt 0 ]; then
- while getoptex "clean build config version package no-package fmodstudio openal ninja vscode jobs: platform: kdu opensim no-opensim singlegrid: avx avx2 crashreporting testbuild: help chan: btype:" "$@" ; do
+ while getoptex "clean build config version package no-package fmodstudio openal ninja vscode jobs: platform: kdu opensim no-opensim singlegrid: avx avx2 tracy crashreporting testbuild: help chan: btype:" "$@" ; do
#ensure options are valid
if [ -z "$OPTOPT" ] ; then
@@ -119,6 +121,7 @@ getArgs()
;;
avx) WANTS_AVX=$TRUE;;
avx2) WANTS_AVX2=$TRUE;;
+ tracy) WANTS_TRACY=$TRUE;;
crashreporting) WANTS_CRASHREPORTING=$TRUE;;
testbuild) WANTS_TESTBUILD=$TRUE
TESTBUILD_PERIOD="$OPTARG"
@@ -308,6 +311,7 @@ else
fi
echo -e " AVX: `b2a $WANTS_AVX`" | tee -a $LOG
echo -e " AVX2: `b2a $WANTS_AVX2`" | tee -a $LOG
+echo -e " TRACY: `b2a $WANTS_TRACY`" | tee -a $LOG
echo -e " CRASHREPORTING: `b2a $WANTS_CRASHREPORTING`" | tee -a $LOG
if [ $WANTS_TESTBUILD -eq $TRUE ] ; then
echo -e " TESTBUILD: `b2a $WANTS_TESTBUILD` ($TESTBUILD_PERIOD days)" | tee -a $LOG
@@ -463,6 +467,11 @@ if [ $WANTS_CONFIG -eq $TRUE ] ; then
else
AVX2_OPTIMIZATION="-DUSE_AVX2_OPTIMIZATION:BOOL=OFF"
fi
+ if [ $WANTS_TRACY -eq $TRUE ] ; then
+ TRACY_PROFILER="-DUSE_TRACY_PROFILER:BOOL=ON"
+ else
+ TRACY_PROFILER="-DUSE_TRACY_PROFILER:BOOL=OFF"
+ fi
if [ $WANTS_TESTBUILD -eq $TRUE ] ; then
TESTBUILD="-DTESTBUILD:BOOL=ON -DTESTBUILDPERIOD:STRING=$TESTBUILD_PERIOD"
else
@@ -531,7 +540,7 @@ if [ $WANTS_CONFIG -eq $TRUE ] ; then
UNATTENDED="-DUNATTENDED=ON"
fi
- cmake -G "$TARGET" ../indra $CHANNEL ${GITHASH} $FMODSTUDIO $OPENAL $KDU $OPENSIM $SINGLEGRID $AVX_OPTIMIZATION $AVX2_OPTIMIZATION $TESTBUILD $PACKAGE \
+ cmake -G "$TARGET" ../indra $CHANNEL ${GITHASH} $FMODSTUDIO $OPENAL $KDU $OPENSIM $SINGLEGRID $AVX_OPTIMIZATION $AVX2_OPTIMIZATION $TRACY_PROFILER $TESTBUILD $PACKAGE \
$UNATTENDED -DLL_TESTS:BOOL=OFF -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE -DCMAKE_BUILD_TYPE:STRING=$BTYPE \
$CRASH_REPORTING -DVIEWER_SYMBOL_FILE:STRING="${VIEWER_SYMBOL_FILE:-}" -DROOT_PROJECT_NAME:STRING=Firestorm $LL_ARGS_PASSTHRU ${VSCODE_FLAGS:-} | tee $LOG